Propert handler question
Alex Martelli
aleax at aleax.it
Fri Oct 31 04:18:42 EST 2003
user at domain.invalid wrote:
> Is there a way, from within a getter/setter method
> linked to a propert, that I can tell which property
> triggered the method?
>
> This would be great, because I need a great number
> of these properties, each having only slightly different
> actions, which could be triggered correctly if
> I knew the name of the property that was being accessed.
So use a closure. E.g, trivial example:
def prop(name):
def getter(self):
print 'getting', name
return getattr(self, '_'+name)
def setter(self, value):
print 'setting', name, 'to', value
return setattr(self, '_'+name, value)
return getter, setter
class WithProperties(object):
foo = property(*prop('foo'))
bar = property(*prop('bar'))
baz = property(*prop('baz'))
w = WithProperties()
w.foo = w.bar = 23
print w.foo, w.bar
will emit:
[alex at lancelot bo]$ python proe.py
setting foo to 23
setting bar to 23
getting foo
23 getting bar
23
Yes, this does require a double specification of the name -- as
an argument to prop AND as the thing you assign to in classbody.
Avoiding this requires black or at least dark-grayish magic, such
as (I've seen others already suggest somewhat-more-magic-yet
solutions requiring both custom metaclasses and custom descriptors,
this one at least makes do with a custom metaclass and a descriptor
_helper_ that gets turned into an ordinary property descriptor:-)...:
class magicprop(object):
def __init__(self, name=''): self.name = name
def getter(self, other):
print 'getting', self.name
return getattr(other, '_'+self.name)
def setter(self, other, value):
print 'setting', self.name, 'to', value
return setattr(other, '_'+self.name, value)
class magicmeta(type):
def __new__(mcl, clasname, clasbase, clasdict):
for n, v in clasdict.items():
if not isinstance(v, magicprop): continue
v.name = n
clasdict[n] = property(v.getter, v.setter)
return type.__new__(mcl, clasname, clasbase, clasdict)
class magic: __metaclass__ = magicmeta
class WithProperties(magic):
foo = magicprop()
bar = magicprop()
baz = magicprop()
w = WithProperties()
w.foo = w.bar = 23
print w.foo, w.bar
this gives the same output as before.
If you do a lot of this you probably don't want to code the
getters and setters right inside the magicprop helper, of
course, but rather code them in the target class and pass
them to magicprop as you'd normally pass them to property.
No problem, actually...:
class magicprop(object):
def __init__(self, getter, setter, name=''):
self.name = name
self.getter = getter
self.setter = setter
def get(self, other):
return self.getter(other, self.name)
def set(self, other, value):
return self.setter(other, self.name, value)
class magicmeta(type):
def __new__(mcl, clasname, clasbase, clasdict):
for n, v in clasdict.items():
if not isinstance(v, magicprop): continue
v.name = n
clasdict[n] = property(v.get, v.set)
return type.__new__(mcl, clasname, clasbase, clasdict)
class magic: __metaclass__ = magicmeta
class WithProperties(magic):
def getter(self, name):
print 'getting', name
return getattr(self, '_'+name)
def setter(self, name, value):
print 'setting', name, 'to', value
setattr(self, '_'+name, value)
foo = magicprop(getter, setter)
bar = magicprop(getter, setter)
baz = magicprop(getter, setter)
w = WithProperties()
w.foo = w.bar = 23
print w.foo, w.bar
and again the output is as usual.
Alex
More information about the Python-list
mailing list