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

Minor annoyances with properties

3 views
Skip to first unread message

eb303

unread,
May 27, 2010, 8:37:36 AM5/27/10
to
Hello all,

I've been using Python properties quite a lot lately and I've found a
few things that are a bit annoying about them in some cases. I
wondered if I missed something or if anybody else has this kind of
problems too, and if there are better solutions than the ones I'm
using ATM.

The first annoyance is when I want to specialize a property in a
subclass. This happens quite often actually, and it is even sometimes
the reason why a plain attribute is turned into a property: a subclass
needs to do more things than the superclass when the property is
updated for example. So, of course, my first try was:

class A(object):
def __init__(self):
self._p = None
def _get_p(self):
return self._p
def _set_p(self, p):
self._p = p
p = property(_get_p, _set_p)
class B(A):
def _set_p(self, p):
## Additional things here…
super(B, self)._set_p(p)

And of course, it doesn't work: the property has been bound to
A._set_p in A, so any new definition of _set_p in any subclass does
not replace the set method for the property. So I always have to add a
line:
p = property(A._get_p, _set_p)
in the subclass too. This is a bit awkward to me, since I have to
specify the superclass's name (super(…) can't be used, since it should
take B as an argument, and B isn't defined yet…). Do I miss something?
Is this the way to do it, or is there a better one?


The second annoyance is when I have a property that is a list of
something. I often have to do something when the contents of the list
is modified. So basically, I often end up doing the following:
def C(object):
def __init__(self):
self._l = []
def _get_l(self):
return list(self._l)
def _set_l(self, l):
self._l = list(l)
l = property(_get_l, _set_l)
But then, I have to do:
o = C()
l = o.l
l.append(42)
o.l = l
instead of just doing:
o.l.append(42)
which would seem much more natural IMHO.

Is there any not too complicated way to have o.l.append(…) call
something in C? And the same for o.l.remove(…), o.l[i] = …, and
everything else updating the list contents?

Thanks!
- Eric -

Neil Cerutti

unread,
May 27, 2010, 9:14:05 AM5/27/10
to
On 2010-05-27, eb303 <eric.brune...@gmail.com> wrote:
> I've been using Python properties quite a lot lately and I've
> found a few things that are a bit annoying about them in some
> cases. I wondered if I missed something or if anybody else has
> this kind of problems too, and if there are better solutions
> than the ones I'm using ATM.

> The first annoyance is when I want to specialize a property in a
> subclass.

See:

URI:http://infinitesque.net/articles/2005/enhancing%20Python%27s%20property.xhtml

--
Neil Cerutti
*** You found a dead moose-rat. You sell the hide for $200. ***

Christian Heimes

unread,
May 27, 2010, 9:24:36 AM5/27/10
to pytho...@python.org
> Do I miss something?
> Is this the way to do it, or is there a better one?

A better way was introduced in Python 2.6. See
http://docs.python.org/library/functions.html?highlight=property#property
I have a Python only version around if you are still using Python 2.5.

Christian

John Posner

unread,
May 27, 2010, 1:10:46 PM5/27/10
to ne...@norwich.edu
On 5/27/2010 9:14 AM, Neil Cerutti wrote:
> On 2010-05-27, eb303<eric.brune...@gmail.com> wrote:
>> I've been using Python properties quite a lot lately and I've
>> found a few things that are a bit annoying about them in some
>> cases. I wondered if I missed something or if anybody else has
>> this kind of problems too, and if there are better solutions
>> than the ones I'm using ATM.
>
>> The first annoyance is when I want to specialize a property in a
>> subclass.
>
> See:
>
> URI:http://infinitesque.net/articles/2005/enhancing%20Python%27s%20property.xhtml
>

Very nice idea, but I think this solution works too hard and not quite
correctly. In Python 2.6.5, checking the name of the OProperty object's
"fget" method:

if self.fget.__name__ == '<lambda>' or not self.fget.__name__:

... doesn't distinguish between the original class's get-the-value
method and the derived class's. (Did something change between 2005-11-02
and now?)

Moreover, you don't *need* to perform this check -- just let *getattr*
do the work of finding the right method. These method defs work fine for me:

def __get__(self, obj, objtype):
if self.fget:
return getattr(obj, self.fget.__name__)()
else:
raise AttributeError, "unreadable attribute"

def __set__(self, obj, value):
if self.fset:
getattr(obj, self.fset.__name__)(value)
else:
raise AttributeError, "can't set attribute"

-John

Francesco Bochicchio

unread,
May 27, 2010, 2:56:29 PM5/27/10
to

Don't know if is better, but you could add a level of indirection to
solve it

class A(object):
def __init__(self):
self._p = None
def _get_p(self):
return self._p
def _set_p(self, p):
self._p = p

def _virtual_get_p (self): _get_p(self)
def _virtual_set_p (self,v): _set_p(self, v)
p = property(_virtual_get_p, _virtual_set_p)

At this point, the subclasses of A can reimplement _get_p and _set_p
as they like (I think)

Ciao
-----
FB


eb303

unread,
May 28, 2010, 5:31:49 AM5/28/10
to
On May 27, 3:24 pm, Christian Heimes <li...@cheimes.de> wrote:
> >  Do I miss something?
> > Is this the way to do it, or is there a better one?
>
> A better way was introduced in Python 2.6. Seehttp://docs.python.org/library/functions.html?highlight=property#prop...

> I have a Python only version around if you are still using Python 2.5.
>
> Christian

Mmmm, I might still miss something. OK, I can replace my initial
property using @property and @p.setter, but it doesn't seem to work in
subclasses:

class A(object):
@property
def p(self):
return self._p
@p.setter


def _set_p(self, p):
self._p = p

class B(A):
@p.setter
def _set_p(self, p):

results in:

Traceback (most recent call last):
File "toto.py", line 8, in <module>
class B(A):
File "toto.py", line 9, in B
@p.setter
NameError: name 'p' is not defined

eb303

unread,
May 28, 2010, 5:36:39 AM5/28/10
to

Well, I've thought about that too and it should work, but that makes 2
function calls instead of one for every property access… I'd really
like to avoid that.

By the way, I think your 'virtual' methods should be written as:
def _virtual_get_p (self): return self._get_p()
def _virtual_set_p (self,v): self._set_p(v)

Thanks anyway.
- Eric -

eb303

unread,
May 28, 2010, 5:46:36 AM5/28/10
to
On May 27, 3:14 pm, Neil Cerutti <ne...@norwich.edu> wrote:

> On 2010-05-27, eb303 <eric.brunel.pragma...@gmail.com> wrote:
>
> > I've been using Python properties quite a lot lately and I've
> > found a few things that are a bit annoying about them in some
> > cases. I wondered if I missed something or if anybody else has
> > this kind of problems too, and if there are better solutions
> > than the ones I'm using ATM.
> > The first annoyance is when I want to specialize a property in a
> > subclass.
>
> See:
>
> URI:http://infinitesque.net/articles/2005/enhancing%20Python%27s%20proper...

>
> --
> Neil Cerutti
> *** You found a dead moose-rat. You sell the hide for $200. ***

Thanks for the suggestion, but it looks a bit heavy… Performing the
name lookup on the specialized object each time the property is
accessed seems a bit overkill. I'd really just like a simple way to
tell in the subclass: now, the setter methof for property p is this
one, only that…

Thanks again anyway.
- Eric -

Christian Heimes

unread,
May 28, 2010, 5:50:56 AM5/28/10
to pytho...@python.org
Am 28.05.2010 11:31, schrieb eb303:
> On May 27, 3:24 pm, Christian Heimes <li...@cheimes.de> wrote:
>>> Do I miss something?
>>> Is this the way to do it, or is there a better one?
>>
>> A better way was introduced in Python 2.6. Seehttp://docs.python.org/library/functions.html?highlight=property#prop...
>> I have a Python only version around if you are still using Python 2.5.
>>
>> Christian
>
> Mmmm, I might still miss something. OK, I can replace my initial
> property using @property and @p.setter, but it doesn't seem to work in
> subclasses:
>
> class A(object):
> @property
> def p(self):
> return self._p
> @p.setter
> def _set_p(self, p):
> self._p = p
> class B(A):
> @p.setter
> def _set_p(self, p):
> �

>
> results in:
>
> Traceback (most recent call last):
> File "toto.py", line 8, in <module>
> class B(A):
> File "toto.py", line 9, in B
> @p.setter
> NameError: name 'p' is not defined

It doesn't work because "p" is not in the scope of B's body while B is
created. You have to write

class B(A):
# access the "p" property from class A
@A.p.setter
def p(self, p):
pass

# once p is in the class body scope, you must not use A.p again
@p.deleter
def p(self):
pass

Christian

eb303

unread,
May 28, 2010, 11:01:29 AM5/28/10
to
On May 28, 11:50 am, Christian Heimes <li...@cheimes.de> wrote:
> Am 28.05.2010 11:31, schrieb eb303:
>
>
>
> > On May 27, 3:24 pm, Christian Heimes <li...@cheimes.de> wrote:
> >>>  Do I miss something?
> >>> Is this the way to do it, or is there a better one?
>
> >> A better way was introduced in Python 2.6. Seehttp://docs.python.org/library/functions.html?highlight=property#prop...
> >> I have a Python only version around if you are still using Python 2.5.
>
> >> Christian
>
> > Mmmm, I might still miss something. OK, I can replace my initial
> > property using @property and @p.setter, but it doesn't seem to work in
> > subclasses:
>
> > class A(object):
> >   @property
> >   def p(self):
> >     return self._p
> >   @p.setter
> >   def _set_p(self, p):
> >     self._p = p
> > class B(A):
> >   @p.setter
> >   def _set_p(self, p):
> >     …

>
> > results in:
>
> > Traceback (most recent call last):
> >   File "toto.py", line 8, in <module>
> >     class B(A):
> >   File "toto.py", line 9, in B
> >     @p.setter
> > NameError: name 'p' is not defined
>
> It doesn't work because "p" is not in the scope of B's body while B is
> created. You have to write
>
> class B(A):
>     # access the "p" property from class A
>     @A.p.setter
>     def p(self, p):
>         pass
>
>     # once p is in the class body scope, you must not use A.p again
>     @p.deleter
>     def p(self):
>         pass
>
> Christian

Well, I still have to explicitely specify the superclass's name then,
so IMHO it's not a big improvement over repeating:
p = property(A._get_p, _set_p)

Thanks anyway…
- Eric -

0 new messages