dynamic, metaclasses and Virtual properties
Ernesto Revilla <[email protected]> Wed, 30 Jun 2004 18:21:53 +0200
| Newsgroups | gmane.comp.python.modeling |
|---|---|
| Message-ID | <[email protected]> |
Hi all,
I think that Python has a design error with properties, but it is easy
to correct this. We can see that in the following example:
class Base(object):
_name=None
def getName(self):
return self._name
def setName(self, value):
self._name=value
name=property(getName,setName)
class Sub(Base):
def setName(self, value):
print "Setting name to '%s'" % value
Base.setName(self,value)
Ok, here we can see how Sub extends the functionality of Base. But if we do:
instance=Sub()
instance.name="a name"
Sub.setName is NOT called.!!! Of course, it cand, because the
property binds directly to the methods. Now we see the Base class
corrected, using 'virtual' properties:
class Base(object):
_name=None
def getName(self):
return self._name
def setName(self, value):
self._name=value
name=property(lambda s: s.getName(), lambda s, v: s.setName(v))
class Sub(Base):
def setName(self, value):
print "Setting name to '%s'" % value
Base.setName(self,value)
An try again:
>>> instance=Sub()
>>> instance.name="a name"
Setting name to 'a name'
In Modeling, when inheriting from class created with properties
(dynamic), it does NOT the inherited methods. Is this reasonable?
Here I have attached a little patch for dynamic.py. I made a local
function mkProp, so that variable binding is correct, otherwise it
does not work the way it should. Just a remark about the setter. As in
the original code, a virtual setter is created only if the attribute is
settable in the base class. In this case, we have two alternatives: 1.
do not create a setter, as the original code, 2. create always a virtual
setter and the setter in the base class raises a
ReadOnlyAttributeException. (This is was I have done in a experimental
framework.)
Best regards, Erny
VirtualProperties.patch
(text/plain, 1.1 KB)
Index: dynamic.py
===================================================================
RCS file: /cvsroot/modeling/ProjectModeling/Modeling/dynamic.py,v
retrieving revision 1.1
diff -u -r1.1 dynamic.py
--- dynamic.py 16 Feb 2004 20:01:06 -0000 1.1
+++ dynamic.py 30 Jun 2004 16:07:47 -0000
@@ -144,10 +144,16 @@
def add_properties(aClass, entity):
for p in entity.classProperties():
#print 'defining prop: ', p.name()
- part_func_name=capitalizeFirstLetter(p.name())
- prop=property(getattr(aClass, 'get'+part_func_name),
- getattr(aClass, 'set'+part_func_name), None)
- setattr(aClass, p.name(), prop)
+ part_func_name=capitalizeFirstLetter(p.name())
+ readonly=not hasattr(aClass,'set'+part_func_name)
+ def mkProp(name, readonly=0):
+ getter=lambda s: getattr(s,'get'+name)()
+ if readonly:
+ setter=None
+ else:
+ setter=lambda s, v: getattr(s,'set'+name)(v)
+ return property(getter, setter)
+ setattr(aClass, p.name(), mkProp(part_func_name, readonly))
def build(model, define_properties=0):
module_name=model.packageName()