Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Overriding properties

0 views
Skip to first unread message

Nick Patavalis

unread,
Dec 11, 2004, 8:06:00 PM12/11/04
to
Why does the following print "0 0" instead of "0 1"? What is the
canonical way to rewrite it in order to get what I obviously expect?

class C(object):
__val = 0
def set_value(self, val):
if val < 0 : self.__val = 0
else : self.__val = val
def get_value(self):
return self.__val
value = property(get_value, set_value)

class CC(C):
def set_value(self, val):
if val < 0: self.__val = 1
else : self.__val = val

c = C()
cc = CC()
c.value = -1
cc.value = -1
print c.value, cc.value

Thanks in advance
/npat

Leif K-Brooks

unread,
Dec 11, 2004, 8:43:44 PM12/11/04
to
Nick Patavalis wrote:
> Why does the following print "0 0" instead of "0 1"? What is the
> canonical way to rewrite it in order to get what I obviously expect?
>
> class C(object):
<snip>

> value = property(get_value, set_value)
>
> class CC(C):
> def set_value(self, val):
<snip>

> c.value = -1
> cc.value = -1
> print c.value, cc.value

The problem is that the names get_value and set_value are evaluated only
once: when class C is first defined. The property has no knowledge of
(or interest in) the fact that a different function named set_value has
been defined.

There are several ways to fix it. The simplest would be to create a new
property object in CC's definition:

class CC(C):
def set_value(self, val):
if val < 0:
self.__val = 1
else:
self.__val = val

value = property(C.get_value, set_value)

But an easier, more flexible method would be to use a metaclass which
automatically adds properties for specially-named methods. One example
of such a metaclass is autoprop from Guido van Rossum's descrintro
essay; see <URL:http://www.python.org/2.2.3/descrintro.html>.

Kay Schluehr

unread,
Dec 12, 2004, 4:36:00 AM12/12/04
to

> There are several ways to fix it. The simplest would be to create a
new
> property object in CC's definition:
>
> class CC(C):
> def set_value(self, val):
> if val < 0:
> self.__val = 1
> else:
> self.__val = val
> value = property(C.get_value, set_value)

It won't fix because __val is defined as a class variable in C, but as
an instance variable in CC. The set_value method creates a new __val. A
typical Python pitfall. C.get_value would still return _C__val.

> But an easier, more flexible method would be to use a metaclass which

> automatically adds properties for specially-named methods. One
example
> of such a metaclass is autoprop from Guido van Rossum's descrintro
> essay; see <URL:http://www.python.org/2.2.3/descrintro.html>.

Yes, but i dislike it either. This powerfull metaclass approach
obscures the property creation right in the place. And it supports the
tendency to create fat frameworks. A few weeks ago i talked to someone
who avoided propertys completely because they seemed to Javaesque to
him. I first agreed and understood his ranting about this awkward
get_bla, set_blubb stuff. Then I rembebered that the property()
function is just a descriptor-creator and one can easily wrap around it
for simplification.

So i defined defprop()

def defprop(name, default = None, modify=None, check=None, types=[]):

name = "__"+name
def get(obj):
if not hasattr(obj,name):
setattr(obj,name, default)
return getattr(obj,name)

def set(obj,value):
if types:
if not True in [isinstance(value,t) for t in types]:
raise TypeError, "Can't assign %s to property
%s."%(value,name[2:])
if check:
if not check(value):
raise TypeError, "Can't assign %s to property
%s."%(value,name[2:])
if modify:
setattr(obj,name,modify(value))
else:
setattr(obj,name,value)

return property(get,set,None)


I left out to define delete. It was for demonstration purposes only.
Now define Your own classes:

class X(object):
a = defprop("a")
b = defprop("b",types=(tuple,list))
c = defprop("c",check = lambda x:hasattr(x,"__len__"))
d = defprop("d",default=0)

class XX(X):
def set_d(val):
if val<0:
return 1
return val

d = defprop("d",default=0,modify=set_d) # overwrite d

It would be nice also to refuse the redundant naming a = defprop("a")
and write
a = defprop() instead. But it's actually not possible at the moment (
or only with deep introspection ).

Session on:

>>> x = X()
>>> x.d
0
>>> xx = XX()
>>> xx.d
0
>>> xx.d = -1
>>> xx.d
1

Ciao
Kay

0 new messages