Propert handler question

U

user

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.

Thanks,

Toby
 
S

Stephen Horne

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.

I don't think so, though I could be wrong.

I'd write one main getter/setter function with an extra parameter for
the property name, then add a whole bunch of noddy getter/setter
functions that provide that extra parameter. Or perhaps a number of
extra parameters - flags to control specific parts of the handlers -
would work better.
 
J

John Roth

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.

The only thing that occurs to me is looking up the call
stack to find what was being accessed. Somehow, that
seems to be the wrong way to approach the problem,
though.

You might want to look at the __getattr__() and
___setattr() magic methods defined in the Python
Language Reference manual (section 3.3.3 in the
Python 2.2.3 manual set.) These are not the easiest
things in the world to program correctly, (setattr in
particular is prone to loops unless you do everything
exactly right) but they
might be what you need in this case, rather than
a boatload of properties.

John Roth
 
B

Bengt Richter

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.
I think you might want to make a custom descriptor class whose
instances you can give names the same as the property they implement.
The get and set methods are the same, but have access to the name parameter
saved in the descriptor instance. E.g., (note that there are two instance "selves"
involved -- the self of the descriptor/property where the individual name is stored,
and the self of the object normally passed to a getter function, but here just
implemented in line, since it is the same for all the descriptor instances in this case.

The following might give you some ideas. The metaclass thing was just to avoid
definining the properties one by one like

class Test(object):
foo = NamedProp('foo')
bar = NamedProp('bar')
baz = NamedProp('baz')
...

(you said there might be a lot of them, so I thought __proplist__ = 'foo bar baz'.split()
would be easier and guarantee the matching of the names bound with the strings passed to the
NamedProp constructor).

A good writeup on the descriptor stuff is Raymond Hettinger's

http://users.rcn.com/python/download/Descriptor.htm

to whom thanks. Also you may want to read

http://www.python.org/2.2.2/descrintro.html

(Hope I haven't misled with the following. Caveat lector? ;-)

====< namedprop.py >=======================================================
class NamedProp(property):
def __get__(pself, oself, otype=None):
"""NamedProp getter"""
if oself is None:
return pself
# implement shared getter code here
# note property instance pself, and object instance oself both available
return pself.name, oself._pval # example of value depending on both
def __set__(pself, oself, val):
"""NamedProp setter"""
# customize as desired
oself._pval = val
def __init__(pself, name):
"""Give property instance a name"""
pself.name = name

class MC_AddNamedProps(type):
"""Automate adding a list of named properties with shared getter/setter code"""
def __new__(cls, cname, cbases, cdict):
for name in cdict.get('__proplist__',[]):
cdict[name]=NamedProp(name)
return type.__new__(cls, cname, cbases, cdict)

class Test(object):
"""Example class with name-carrying properties"""
__metaclass__ = MC_AddNamedProps
__proplist__ = 'foo bar baz'.split()
def __init__(self, val=None): self._pval=val

def test():
t1 = Test(111)
print 't1:',t1
print 't1.foo => %r' % (t1.foo,)
print 't1.bar => %r' % (t1.bar,)
print 't1.baz => %r' % (t1.baz,)
print 't1.foo = <new value via t1.foo> =>'
t1.foo = '<new value via t1.foo>'
print 't1.foo => %r' % (t1.foo,)
print 't1.bar => %r' % (t1.bar,)
print 't1.baz => %r' % (t1.baz,)
if __name__ == '__main__':
test()
====< namedprop.py >=======================================================

Result:

[22:35] C:\pywk\clp\descr>namedprop.py
t1: <__main__.Test object at 0x0090B310>
t1.foo => ('foo', 111)
t1.bar => ('bar', 111)
t1.baz => ('baz', 111)
t1.foo = <new value via t1.foo> =>
t1.foo => ('foo', '<new value via t1.foo>')
t1.bar => ('bar', '<new value via t1.foo>')
t1.baz => ('baz', '<new value via t1.foo>')

Regards,
Bengt Richter
 
A

Alex Martelli

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@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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top