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

Override property setter of base class in Python 3

1,739 views
Skip to first unread message

Nagy László Zsolt

unread,
Sep 11, 2016, 5:53:47 AM9/11/16
to
Example code:


class A:
def __init__(self, prop=0):
self.__prop = prop

@property
def prop(self):
return self.__prop

@prop.setter
def prop(self, value):
self.__prop = value

class B(A):
@A.prop.setter
def prop(self, value):
print("Setting new value",value)
super().prop = value


b = B(0)
b.prop=10

Result:

Setting new value 10
Traceback (most recent call last):
File "test.py", line 22, in <module>
b.prop=10
File "test.py", line 18, in prop
super().prop = value
AttributeError: 'super' object has no attribute 'prop'

This seems to be working:


class B(A):
@A.prop.setter # MAGIC HERE!
def prop(self, value):
print("Setting new value",value)
A.prop.fset(self, value) # MAGIC HERE!

How can I remove the magic? E.g. referencing the base class name
directly, and using some internal name "fset"?

Also, consider this:


class A:
def __init__(self, prop=0):
self.__prop = prop

@property
def prop(self):
return self.__prop

@prop.setter
def prop(self, value):
self.__prop = value


class B(A):
@A.prop.setter
def prop(self, value):
print("Setting new value in B:",value)
A.prop.fset(self, value) # How use the MRO here?

class C(A):
@A.prop.setter
def prop(self, value):
print("Setting new value in C:",value)
A.prop.fset(self, value) # How use the MRO here?

class D(B,C):
pass


d = D(0)
d.prop=10

Result:

Setting new value in B: 10

What if I want to use the "property setter of the superclass"? E.g. the
one that is the next in the MRO?

Thanks,

Laszlo




Nagy László Zsolt

unread,
Sep 11, 2016, 6:03:26 AM9/11/16
to
By the way, I know that I can use a "property virtualizer", something
like this:

import inspect

class A:
def __init__(self, prop=0):
self.__prop = prop

def _prop_get(self):
return self.__prop

def _prop_set(self, value):
self.prop_set(value)

def prop_set(self, value):
print("Setting prop value in A to", value)
self.__prop = value

prop = property(_prop_get, _prop_set)


class B(A):
def prop_set(self, value):
print("Setting prop value in B to", value)
super().prop_set(value)

class C(A):
def prop_set(self, value):
print("Setting prop value in C to", value)
super().prop_set(value)

class D(B,C):
pass


d = D(0)
d.prop=10


But this solution almost defeats the purpose of properties. E.g. a
property should look like an attribute, and its behaviour should be
manipulated through its name (and not another special method that must
be exposed to subclasses.)

Chris Angelico

unread,
Sep 11, 2016, 6:12:42 AM9/11/16
to
On Sun, Sep 11, 2016 at 8:02 PM, Nagy László Zsolt <gan...@shopzeus.com> wrote:
> But this solution almost defeats the purpose of properties. E.g. a
> property should look like an attribute, and its behaviour should be
> manipulated through its name (and not another special method that must
> be exposed to subclasses.)

Even the problem seems to rather defeat the purpose of a property. A
property should be very simple - why do you need to override it and
call super()? Doesn't this rather imply that you've gone beyond the
normal use of properties *already*?

Subclassing and overriding are part of the interface of a class,
albeit an interface that only a subset of other classes will use.
Think carefully about why, if this is meant to be made available, it
isn't simply a method call.

ChrisA

Nagy László Zsolt

unread,
Sep 11, 2016, 7:18:09 AM9/11/16
to

> Even the problem seems to rather defeat the purpose of a property. A
> property should be very simple - why do you need to override it and
> call super()? Doesn't this rather imply that you've gone beyond the
> normal use of properties *already*?
I'm not sure about that. I'm going to send a USE CASE in a separate
message.

>
> Subclassing and overriding are part of the interface of a class,
> albeit an interface that only a subset of other classes will use.
> Think carefully about why, if this is meant to be made available, it
> isn't simply a method call.

Properties are also part of the class interface. I don't see any good
reason why property get and set methods should not be overridden in
subclasses.

Provisional syntax:

class A:
def __init__(self, prop=0):
self.__prop = prop

@property
def prop(self):
return self.__prop

@prop.setter
def prop(self, value):
self.__prop = value

class B(A):
@super.prop.getter
def prop(self):
print("Getting value",super().prop)
return super().prop

@super.prop.setter
def prop(self, value):
print("Setting new value",value)
super().prop = value


The only problem is that we cannot access "the property setter
implementation of the superclass" easily.

There is already a standard working way to overcome this: property
virtualizer methods. (See my second email.) That pattern *allows
attribute like access and polimorphism at the same time*, but at the
cost of making the class interface more difficult and harder to
understand. I only asked for a way to remove the seemingly neccessary
bolierplate code ("syntax noise") and make it cleaner.

Laszlo


Chris Angelico

unread,
Sep 11, 2016, 8:03:29 AM9/11/16
to
On Sun, Sep 11, 2016 at 9:17 PM, Nagy László Zsolt <gan...@shopzeus.com> wrote:
>> Subclassing and overriding are part of the interface of a class,
>> albeit an interface that only a subset of other classes will use.
>> Think carefully about why, if this is meant to be made available, it
>> isn't simply a method call.
>
> Properties are also part of the class interface. I don't see any good
> reason why property get and set methods should not be overridden in
> subclasses.

Right, I'm not saying they aren't; I'm just saying that properties are
intended for simpler purposes than you'll normally need subclassing
for.

I'll wait for your follow-up email with a use case.

ChrisA
0 new messages