unine...@gmail.com wrote:
class Person:
def __init__(self):
for prop in props:
setattr(self, "__" + prop[0], prop[1])
setattr(Person, "Get" + prop[0], lambda self: getattr
(self, "__" + prop[0]))
I've had a similar problem here and here is best how I can explain it.
The prop in the lambda function is a closure by 'name' to the prop in
the containing name space (__init__), so when the lambda function
executes, it looks for the name 'prop' in this name space and uses it's
value. After the 'for prop in props' loop is complete, 'prop' is left
referring to the last item in props, so each lambda function would use
it (mary)
One solution is to not use lambda and avoid closures by using default
arguments:
for prop in props:
def Getter(self=self, prop=prop):
return getattr(self, '__' + prop[0])
setattr(self, '__' + prop[0], prop[1])
setattr(self, 'Get' + prop[0], Getter)
I have several problems with this though:
1. I don't think this will invoke Pythons name mangling mechanism. The
property will be '__name' and not '__Person_name'.
2. If you make a copy of the class, including attributes, the Getter
will operate on the old class not new:
Person a
b = copy.copy(a)
setattr(a, '__name', bob)
setattr(b, '__name', sarah)
b.Getname() -> bob
In order to make it work, the class must support updating the Getter
when it is copied to have a new self value.
import copy
class MethodCaller:
def __init__(self, obj, method, name):
self.obj = obj
self.method = method
self.name = name
setattr(obj, name, self)
def __call__(self, *args, **kwargs):
return self.method(self.obj, *args, **kwargs)
def copy(self, newobj):
return MethodCaller(newobj, self.method, self.name)
props = ( ('name', 'mary'), ('age', 21), ('gender', 'female') )
class Person:
def __init__(self):
self._methods = []
for prop in props:
(name, value) = prop
def getter(self, name=name):
return getattr(self, '_' + name)
setattr(self, '_' + name, value)
self._methods.append(MethodCaller(self, getter, 'Get' + name))
def copy(self,copymethods=True):
c = copy.copy(self)
if copymethods:
c._methods = []
for i in self._methods:
c._methods.append(i.copy(c))
return c
# Example without copying methods
p = Person()
q = p.copy(False)
p._name = 'sarah'
q._name = 'michelle'
print p.Getname()
print p.Getage()
print p.Getgender()
print q.Getname() # Still prints 'sarah', because getter still refers to
'p' instead of 'q'
print q.Getage()
print q.Getgender()
# Example with copying methods
p = Person()
q = p.copy()
p._name = 'sarah'
q._name = 'michelle'
print p.Getname()
print p.Getage()
print p.Getgender()
print q.Getname() # Prints 'michelle'
print q.Getage()
print q.Getgender()
--
http://mail.python.org/mailman/listinfo/python-list