Discussion:
[Modeling-users] dynamic, metaclasses and Virtual properties
Ernesto Revilla
2004-06-30 14:25:06 UTC
Permalink
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)
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
John Lenton
2004-06-30 21:18:01 UTC
Permalink
Post by Ernesto Revilla
Hi all,
I think that Python has a design error with properties, but it is easy
properties are evil; stay away from them. They are usful for one thing
and one thing only: replacing buggy classes that used attributes.

IMHO :)
--
John Lenton (***@vialibre.org.ar) -- Random fortune:
You know what they say -- the sweetest word in the English language is revenge.
-- Peter Beard
Sebastien Bigaret
2004-08-07 11:31:04 UTC
Permalink
Hi Erny and all,

On Wed, 30 Jun 2004, Ernesto Revilla <***@sicem.biz> wrote:
[original post can be found at:
https://sf.net/mailarchive/forum.php?thread_id=5035017&forum_id=10674]
I think that Python has a design error with properties, but it is easy to
correct this.
[demonstration that properties aint behaving very good when it comes to
inheritance]
In Modeling, when inheriting from class created with properties (dynamic), it
does NOT the inherited methods. Is this reasonable?
You're right, this needs some attention, really. Could you submit this
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.
Can you be more explicit on this point?
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.)
For the moment being we're not handling any 'readOnly' properties on
attributes --and the one in entity is still ignored for now, so I can't
really see whazt your point is, I suspect I'm misunderstanding something
here.

Oh, and BTW sorry for taking such a long time to answer :/

-- Sébastien.
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 @@
#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)
+ getter=lambda s: getattr(s,'get'+name)()
+ setter=None
+ setter=lambda s, v: getattr(s,'set'+name)(v)
+ return property(getter, setter)
+ setattr(aClass, p.name(), mkProp(part_func_name, readonly))
module_name=model.packageName()
Ernesto Revilla
2004-08-09 09:32:01 UTC
Permalink
Post by Sebastien Bigaret
Hi Erny and all,
https://sf.net/mailarchive/forum.php?thread_id=5035017&forum_id=10674]
I think that Python has a design error with properties, but it is easy to
correct this.
[demonstration that properties aint behaving very good when it comes to
inheritance]
In Modeling, when inheriting from class created with properties (dynamic), it
does NOT the inherited methods. Is this reasonable?
Sometimes I just forget the VERB. I mean 'apply' behind 'NOT' in the
previous sentence. Properties bind directly to methods/functions (read
method, write method, delete method). This is the result of descriptors
implemented in python 2.2. There is still no syntactic sugar to use
'virtualized' properties.
Post by Sebastien Bigaret
You're right, this needs some attention, really. Could you submit this
I've sent a patch proposal.
Post by Sebastien Bigaret
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.
Can you be more explicit on this point?
As you can see in the mkProp I create the methods like this:

getter=lambda s: getattr(s,'get'+name)()

Now, as lambda is evaluated, when it is called, it depends of what is
the binding of the 'name' variable at this time. If I leave this outside
of a function and I have this is called several times, name changes,
and at the end will have the last assigned value, so all getters created
with the statement will refere effectively to the same attribute, as all
getters will evaluate 'name' to the same value. Say you have 3
attributes: name, surname and age, and call the above statement, 3 times
in the same order for each attribute, you'll get 3 functions, but all
the three functions will call getAge, because 'name' will bind to 'age'.
To force the binding, I built the mkProp function and put the
statement ( getter=lambda s: getattr(s,'get'+name)() ) into the
function body. This forces to copy the binding to a local variable, the
function parameter. So each time I call mkProp, name will be bound to
another value, and will be retained as the lambda expression refers to it.

I think the same thing can be accomplished in another way, e.g. as you
do by creating methods from source code. I still haven't tried using
this approach.
Post by Sebastien Bigaret
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.)
For the moment being we're not handling any 'readOnly' properties on
attributes --and the one in entity is still ignored for now, so I can't
really see whazt your point is, I suspect I'm misunderstanding something
here.
I used that for a mini testing framework I wrote, where i defined
read-only attributes. So, please ignore it at this time.
Post by Sebastien Bigaret
Oh, and BTW sorry for taking such a long time to answer :/
No problem at all. I just wanted to make the point clear of using
properties.

Regards, Erny
Ernesto Revilla
2004-08-09 13:35:01 UTC
Permalink
Post by Sebastien Bigaret
Hi Erny and all,
https://sf.net/mailarchive/forum.php?thread_id=5035017&forum_id=10674]
I think that Python has a design error with properties, but it is easy to
correct this.
[demonstration that properties aint behaving very good when it comes to
inheritance]
In Modeling, when inheriting from class created with properties (dynamic), it
does NOT the inherited methods. Is this reasonable?
Sometimes I just forget the VERB. I mean 'apply' behind 'NOT' in the
previous sentence. Properties bind directly to methods/functions (read
method, write method, delete method). This is the result of descriptors
implemented in python 2.2. There is still no syntactic sugar to use
'virtualized' properties.
Post by Sebastien Bigaret
You're right, this needs some attention, really. Could you submit this
I've sent a patch proposal.
Post by Sebastien Bigaret
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.
Can you be more explicit on this point?
As you can see in the mkProp I create the methods like this:

getter=lambda s: getattr(s,'get'+name)()

Now, as lambda is evaluated, when it is called, it depends of what is
the binding of the 'name' variable at this time. If I leave this outside
of a function and I have this is called several times, name changes,
and at the end will have the last assigned value, so all getters created
with the statement will refere effectively to the same attribute, as all
getters will evaluate 'name' to the same value. Say you have 3
attributes: name, surname and age, and call the above statement, 3 times
in the same order for each attribute, you'll get 3 functions, but all
the three functions will call getAge, because 'name' will bind to 'age'.
To force the binding, I built the mkProp function and put the
statement ( getter=lambda s: getattr(s,'get'+name)() ) into the
function body. This forces to copy the binding to a local variable, the
function parameter. So each time I call mkProp, name will be bound to
another value, and will be retained as the lambda expression refers to it.

I think the same thing can be accomplished in another way, e.g. as you
do by creating methods from source code. I still haven't tried using
this approach.
Post by Sebastien Bigaret
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.)
For the moment being we're not handling any 'readOnly' properties on
attributes --and the one in entity is still ignored for now, so I can't
really see whazt your point is, I suspect I'm misunderstanding something
here.
I used that for a mini testing framework I wrote, where i defined
read-only attributes. So, please ignore it at this time.
Post by Sebastien Bigaret
Oh, and BTW sorry for taking such a long time to answer :/
No problem at all. I just wanted to make the point clear of using
properties.

Regards, Erny

Loading...