I am attempting to create python bindings for some C++ code using swig. I seem have run into a problem trying to create python properties from some accessor functions I have for
The problem with Hao's ProperyVoodoo metaclass is that when there are multiple properties in the properties list, all the properties behave the same as the last one in the list. For example, if I had a list or property names ["x", "y", "z"], then the properties generated for all three would use the same accessors as "z".
After a little experimentation I believe I've determined that this problem is caused by the way Python handles closures (ie. names within nested functions that refer to variables in the containing scope). To solve the problem, you need to get local copies of the property name variable into the fget and fset methods. It's easy enough to sneak them in using default arguments:
# (NOTE: Hao's comments removed for brevity)
class PropertyVoodoo(type):
def __init__(cls, *a):
for prop in cls.__properties__:
def fget(self, _prop = str(prop)):
s = super(cls, self)
return getattr(s, _prop)()
def fset(self, value, _prop = str(prop)):
s = super(cls, self)
return getattr(s, _prop)(value)
setattr(cls, prop, property(fget=fget, fset=fset))
super(PropertyVoodoo, cls).__init__(*a)
def __setattr__(self, name, value):
if name in cls.__properties__:
object.__setattr__(self, name, value)
else:
s = super(cls, self)
s.__setattr__(name, value)
cls.__setattr__ = __setattr__
Note that it is, in fact, completely safe to give fget and fset the extra _prop parameters because the property() class will never explicitly pass values to them, which means they will always be the default value (that being a copy of the string referenced by prop at the time each fget and fset method was created).