problem with defining setters and getters
Alex Martelli
aleax at aleax.it
Wed Mar 12 12:34:00 EST 2003
John Hunter wrote:
>
>
> I have a class that is initialized with another object that has
> certain attributes I want to expose to the class with getters and
> setters. I am doing this
>
> class Entry:
> def __init__(self):
> self.pid = 1
> self.somevar = 2
>
> def get_field_names(self):
> return ['pid', 'somevar']
>
> class MyClass:
> def __init__(self, entry):
> self.entry = entry
>
> for name in entry.get_field_names():
> def get_func(): return getattr(self.entry, name)
> def set_func(val): return setattr(self.entry, name, val)
Note that these get_func and set_func functions you are defining do no
re-binding at all of 'name' at the time of definition -- rather, they
all rely on whatever value 'name' is bound to in their lexically
surrounding scope *at the time they execute*. So, clearly they MUST
be all using the same value for 'name', yes?
> setattr(self, 'get_' + name, get_func)
> setattr(self, 'set_' + name, set_func)
>
>
>
> entry = Entry()
> c = MyClass(entry)
>
> c.set_somevar('John')
> print c.get_pid()
>
>
> entry has a function get_field_names that returns a list of attributes
> that I want to expose. pid is one of those attributes, and I am
> calling set_pid and get_pid as a test case.
>
> The problem is that all of the getters and setters take on the last
> attribute returned by field names. That is, get_pid returns 'John' in
> the example above, and I want it to return 1. It appears that there
> is only one get_func in the __init__ loop, and all of the getters are
> using this func. Likewise for set_func.
No, there are many get_func and set_func objects created, but all of
them choose to use the same binding for 'name' (in their lexically
enclosing scope). For your purposes you seem to want to re-bind that
at function-definition time -- very well, then DO so, e.g. by:
def get_func(name=name): return getattr(self.entry, name)
def set_func(val, name=name): return setattr(self.entry, name, val)
and you're all set -- this is just one of several equivalent approaches,
using the fact that default values are evaluated at definition-time, but
if you're uncomfortable with that you may choose different approaches,
such for example as the following:
def __init__(self, entry):
def make_get_set(name):
def get_func(): return getattr(entry, name)
def set_func(val): return setattr(entry, name, val)
return get_func, set_func
for name in entry.get_field_names():
get_func, set_func = make_get_set(name)
setattr(self, 'get_' + name, get_func)
setattr(self, 'set_' + name, set_func)
here, in make_get_set, I'm exploiting the lookup of entry in
the lexically surrounding scope (thus not binding self.entry --
it's not necessary in this example) but re-binding 'name' by
simple argument-passing.
Alex
More information about the Python-list
mailing list