property and virtuality

L

Laszlo Zsolt Nagy

My problem is about properties and the virtuality of the methods. I
would like to create a property whose get and set methods
are virtual. I had the same problems in Delphi before and the solution
was the same. I created a private _get method and a public
get method. The former one will call the latter. The same stands for
_set and set. Here is an example below:

class C1(object):
def namechanged(self):
"""Called after the name of the component has been changed."""
pass
def getname(self):
"""Returns the name of the component.

You can override this method to provide generated component
names."""
return self._name
def setname(self,name):
"""Set the name of the component.

You can override this method to programatically control
component name changes.
"""
self._name = name
self.namechanged()
def _getname(self):
"""Internal method, do not use"""
return self.getname()
def _setname(self,name):
"""Internal method, do not use"""
self.setname(name)
name = property(_getname,_setname,"Name")

class C2(C1):
def getname(self):
return "lala"

class C3(C1):
def _getname(self):
return "lala"
name = property(_getname,None,"Name")


c1 = C1()
c2 = C2()
c3 = C3()

c1.name = 'Test1'
c2.name = 'Test2'
c3.name = 'Test3'
print c1.name # This will print 'Test1'
print c2.name # This will print 'lala'
print c3.name # This will print 'lala'
print C3.name is C1.name # False

I cannot override C2._getname instead, because c2.name would print
'Test2" instead of lala. Clearly, the property stores a reference to the
get and set methods and it is not possible to have it use the new
methods. Creating a new property is the worst - need to duplicate code
and also C3.name is C1.name returns False. :) It is not a big problem
because I found the solution just I wonder if there is a better way to
"virtualize" property get/set functions.




--
_________________________________________________________________
Laszlo Nagy web: http://designasign.biz
IT Consultant mail: (e-mail address removed)

Python forever!
 
L

Laszlo Zsolt Nagy

I'm not aware of possibility that works as you first expected. You yourself
explained why.

But _maybe_ you can use lambda here - that creates the layer of indirection
one needs.

foo = property(lambda self: self.get_foo(), lamda self,v: self.set_foo(v))
Great. I'll think about this and decide which is better - lamba or
private functions. Lambda seems much
shorter but it is not as clear why it is there. :)
On second thoughts, a metaclass _might_ help here - but it would be rather
elaborate: look in the baseclasses for properties that have getters and
setters of the same name as some methods in the current class, and replace
them, or create a new property with them (I'm not sure if descriptors
allow changing their get/set/del methods). I'm not 100% sure if and how
good that works (a quick hack would be easy, but to ship around the cliffs
of multiple inheritance requires more careful navigation I fear...)
Yes, I feel the same. Using a metaclass could be a small help but rather
elaborate and probably much slower.
Thank you for your help.


--
_________________________________________________________________
Laszlo Nagy web: http://designasign.biz
IT Consultant mail: (e-mail address removed)

Python forever!
 
D

Diez B. Roggisch

I cannot override C2._getname instead, because c2.name would print
'Test2" instead of lala. Clearly, the property stores a reference to the
get and set methods and it is not possible to have it use the new
methods. Creating a new property is the worst - need to duplicate code
and also C3.name is C1.name returns False. :) It is not a big problem
because I found the solution just I wonder if there is a better way to
"virtualize" property get/set functions.

I'm not aware of possibility that works as you first expected. You yourself
explained why.

But _maybe_ you can use lambda here - that creates the layer of indirection
one needs.

foo = property(lambda self: self.get_foo(), lamda self,v: self.set_foo(v))

On second thoughts, a metaclass _might_ help here - but it would be rather
elaborate: look in the baseclasses for properties that have getters and
setters of the same name as some methods in the current class, and replace
them, or create a new property with them (I'm not sure if descriptors
allow changing their get/set/del methods). I'm not 100% sure if and how
good that works (a quick hack would be easy, but to ship around the cliffs
of multiple inheritance requires more careful navigation I fear...)
 
D

Diez B. Roggisch

Great. I'll think about this and decide which is better - lamba or
private functions. Lambda seems much
shorter but it is not as clear why it is there. :)

I did put comments above each property line - so one might argue that's
about the same effort as writing the method explicit. Alternatively, you
could introduce a naming scheme in the getters/setters that are supposed to
be overloaded so that it becomes clear - at least for someone knowing the
project. But that's true for the whole thingy :)
Yes, I feel the same. Using a metaclass could be a small help but rather
elaborate and probably much slower.

Certainly not much slower - that happens once, at class creation time - and
the results would even be faster, as you can skip the layer of indirection.
 
M

Michele Simionato

I think you may find Alex Martelli's PyCon slides somewhere
on the net. The black magic slides discuss this issue. But I
think the fix he suggests is not dissimilar from what you
are already doing. I don't remember exactly now, but
it is always worth a look.

Michele Simionato
 
S

Steven Bethard

Laszlo said:
My problem is about properties and the virtuality of the methods. I
would like to create a property whose get and set methods
are virtual.

Perhaps you want to roll your own VirtualProperty descriptor? Here's
one based off the property implementation in Raymond Hettinger's How-To
Guide for Descriptors[1]:

py> class VirtualProperty(object):
.... def __init__(self, getname=None, setname=None, delname=None,
.... doc=None):
.... self.getname = getname
.... self.setname = setname
.... self.delname = delname
.... self.__doc__ = doc
.... def __get__(self, obj, type=None):
.... if obj is None:
.... return self
.... if self.getname is None:
.... raise AttributeError('unreadable attribute')
.... try:
.... fget = getattr(obj, self.getname)
.... except AttributeError:
.... raise TypeError('%s object does not have a %s method' %
.... (type(obj).__name__, self.getname))
.... return fget()
.... def __set__(self, obj, value):
.... if self.setname is None:
.... raise AttributeError("can't set attribute")
.... try:
.... fset = getattr(obj, self.setname)
.... except AttributeError:
.... raise TypeError('%s object does not have a %s method' %
.... (type(obj).__name__, self.setname))
.... fset(value)
.... def __delete__(self, obj):
.... if self.delname is None:
.... raise AttributeError("can't delete attribute")
.... try:
.... fdel = getattr(obj, self.delname)
.... except AttributeError:
.... raise TypeError('%s object does not have a %s method' %
.... (type(obj).__name__, self.delname))
.... fdel()
....
py> class C(object):
.... def getx(self):
.... return 'C'
.... x = VirtualProperty('getx', 'setx', 'delx')
....
py> class D(C):
.... def getx(self):
.... try:
.... return self._x
.... except AttributeError:
.... return 'D'
.... def setx(self, x):
.... self._x = x
....
py> c = C()
py> c.x
'C'
py> c.x = 1
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "<interactive input>", line 24, in __set__
TypeError: C object does not have a setx method
py> del c.x
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "<interactive input>", line 33, in __delete__
TypeError: C object does not have a delx method
py> d = D()
py> d.x
'D'
py> d.x = 1
py> d.x
1
py> del d.x
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
File "<interactive input>", line 33, in __delete__
TypeError: D object does not have a delx method

STeVe

[1] http://users.rcn.com/python/download/Descriptor.htm
 
H

harold fellermann

Hello,

I asked this question some time ago, but as I got no answer, so I just
try it a second
time.

I am working on a C extension module that implements a bunch of
classes. Everything
works fine so far, but I cannot find any way to implement class
attributes or inner
classes. Consider you have the following lines of Python :

class Foo :
class Bar :
pass

spam = "foobar"

How can this class be translated to a C extension? Is there anything
comparable to
PyMethodDef that can be used for other attributes than functions?

Thanks for your help,

- harold -
 
S

Steven Bethard

Steven said:
Laszlo said:
My problem is about properties and the virtuality of the methods. I
would like to create a property whose get and set methods
are virtual.

Perhaps you want to roll your own VirtualProperty descriptor? Here's
one based off the property implementation in Raymond Hettinger's How-To
Guide for Descriptors[1]:

This comes up often enough I figured it would be worth posting this as a
recipe:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/408713

STeVe
 
T

Terry Reedy

harold fellermann said:
I asked this question some time ago, but as I got no answer, so I just
try it a second time.

This did get out, but I can't answer except to suggest looking at code for
other C extension modules. Nested (inner) classes are fairly rare, but I
presume that once you know how to add attributes in general, you add class
as an attribute in the same way you would add an int, etc, as an attribute.
(And if I am wrong, you should certainly get another response '-).

Terry J. Reedy
 
B

boisgera

Laszlo Zsolt Nagy said:
My problem is about properties and the virtuality of the methods. I
would like to create a property whose get and set methods
are virtual. I had the same problems in Delphi before and the solution
was the same. I created a private _get method and a public
get method. The former one will call the latter.
[...]
I cannot override C2._getname instead, because c2.name would print
'Test2" instead of lala. Clearly, the property stores a reference to the
get and set methods and it is not possible to have it use the new
methods. Creating a new property is the worst - need to duplicate code
and also C3.name is C1.name returns False. :) It is not a big problem
because I found the solution just I wonder if there is a better way to
"virtualize" property get/set functions.

Alex Martelli has demonstrated the same technique to "fix" this
disturbing property behavior during one of its talk at Pycon 2005:

http://www.python.org/pycon/2005/papers/36/ (slides p.7&8)

.... from this I infer that you found the best fix available ;)

Regards,

Sébastien
 
M

Michele Simionato

Diez B. Roggisch:
On second thoughts, a metaclass _might_ help here - but it would be rather
elaborate: look in the baseclasses for properties that have getters and
setters of the same name as some methods in the current class, and replace
them, or create a new property with them (I'm not sure if descriptors
allow changing their get/set/del methods). I'm not 100% sure if and how
good that works (a quick hack would be easy, but to ship around the cliffs
of multiple inheritance requires more careful navigation I fear...)

Maybe you are worrying to much. Here is a quick metaclass solution
which
magically generates properties from methods which name starts with
"get"
or "set":

class MagicProperties(type):
def __init__(cls, name, bases, dic):
prop_names = set(name[3:] for name in dic
if name.startswith("get")
or name.startswith("set"))
for name in prop_names:
getter = getattr(cls, "get" + name, None)
setter = getattr(cls, "set" + name, None)
setattr(cls, name, property(getter, setter))

class Base(object):
__metaclass__ = MagicProperties
def getx(self):
return self._x
def setx(self, value):
self._x = value

class Child(Base):
def getx(self):
print "getting x"
return super(Child, self).getx()
def setx(self, value):
print "setting x"
super(Child, self).setx(value)

c = Child()
c.x = 1
print c.x

This should work well for multiple inheritance too (modulo metaclass
conflicts).

I must say, however, that I never use this idiom (i.e. polluting my
classes
with tons of getters and setters and making properties from them).
I typically use a property factory function, or a custom descriptor.


Michele Simionato
 
G

Greg Ewing

Laszlo said:
My problem is about properties and the virtuality of the methods. I
would like to create a property whose get and set methods
are virtual.

You might find the following function useful, which I
developed for use in PyGUI.

def overridable_property(name, doc = None):
"""Creates a property which calls methods get_xxx and set_xxx of
the underlying object to get and set the property value, so that
the property's behaviour may be easily overridden by subclasses."""

getter_name = intern('get_' + name)
setter_name = intern('set_' + name)
return property(
lambda self: getattr(self, getter_name)(),
lambda self, value: getattr(self, setter_name)(value),
None,
doc)

Usage example:

class MyClass(object):
...
spam = overridable_property('spam', "Favourite processed meat product")
...
 

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

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top