Discussion:
Override property setter of base class in Python 3
(too old to reply)
Nagy László Zsolt
2016-09-11 09:46:16 UTC
Permalink
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
2016-09-11 10:02:49 UTC
Permalink
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
2016-09-11 10:12:27 UTC
Permalink
Post by Nagy László Zsolt
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
2016-09-11 11:17:49 UTC
Permalink
Post by Chris Angelico
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.
Post by Chris Angelico
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
Nagy László Zsolt
2016-09-11 11:31:38 UTC
Permalink
Post by Chris Angelico
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*?
Here are some of my classes that can represent data:

"FormField" - a field of a form that have some properties (name, label,
description, required or not, value etc.) They are available as
properties e.g. formfield.value, formfield.required etc.
"Form" - a collection of FormFields that can be used to validate the
form as a whole.

Some data structures are represented in FormField and Form instances.
They are *often* represented to the user on a user interface. But
*sometimes* they are used in other ways.

The user interface is built on top of a "Widget" class, that knows how
to build ui elements for the user (in this case: in a web browser). It
can send/receive messages to/from the browser. Widget objects also have
basic properties (for example: color, size, parent widget etc.) Whenever
a property is changed on a widget object, the change is accounted for,
goes through some buffering and sent to the browser. When I do
"widget.visible = False" then it will (eventually) send a message to the
browser and execute javascript code something like this:

jQuery("#some_widget_id").hide()

When a FormField needs a visual representation, then I create subclasses
that inherit from both Widget and FormField. For example, a "TextField"
class. Some properties that are defined in FormField must also be
represented visually. The synchronization between property values and
visual elements is done with messages/events. For example, when I do

textfield.value = "some value"

then the property value is updated internally in the FormField, but it
also creates a message that will be sent to the browser and update the
value attribute of the <input> element. As a result, the user will also
see that the value has been changed. On the other hand, when the user
changes the value in the <input> field, a message is pushed from the
browser to the TextField object, and that will also change the value of
the corresponding textfield.value property.

The "value of a form field" must have a unified interface. So when I do
" textfield.value = some_value " then I expect that the changed value
will be represented on the UI *if it has an UI representation*. The
widget needs to be able to intercept property value changes.

One solution would be to make FormField an observable object, define
separate events for these property changes (e.g. EVT_VALUE_CHANGED), and
let TextField listen to these events. But this is even more difficult
than using simple methods and overriding them. We know that there will
only be a single chain of observers. Using an observable pattern that
can have many observers for a single event seems to be an overkill.
Using overriden setter methods instead of properties is still better
than using the observable/observer pattern. Much more simple and easier
to understand.

Does this go beyond the normal use of properties? You decide. I'm open
to suggestions. What other pattern can I use for this problem?

Here are the possibilities I see:

* Use property virtualizers - too much syntax noise, but at least
boilerplate code is contained within the class and it works as
expected (this is what I use now)
* Use getter/setter methods instead of properties - non-pythonic
* Use the observable pattern, emit events for property changes and
make others listen for it - too general and too difficult for this
problem, harder to understand
* Propose a new syntax that allows proper overriding of property
getter/setter methods without too much syntax noise

Laszlo
Chris Angelico
2016-09-11 12:03:08 UTC
Permalink
Post by Nagy László Zsolt
Post by Chris Angelico
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
Chris Angelico
2016-09-11 12:05:46 UTC
Permalink
Post by Nagy László Zsolt
The "value of a form field" must have a unified interface. So when I do
" textfield.value = some_value " then I expect that the changed value
will be represented on the UI *if it has an UI representation*. The
widget needs to be able to intercept property value changes.
Does this go beyond the normal use of properties? You decide. I'm open
to suggestions. What other pattern can I use for this problem?
Yes, I believe it does. (Others may disagree. This is a design
question and very much a matter of style, not hard fact.) I would have
an explicit action "set_content" which will set the value of an input
field, the inner text of a textarea, the checked state of a check box,
etc.

ChrisA
Nagy László Zsolt
2016-09-11 13:21:51 UTC
Permalink
Post by Chris Angelico
Yes, I believe it does. (Others may disagree. This is a design
question and very much a matter of style, not hard fact.) I would have
an explicit action "set_content" which will set the value of an input
field, the inner text of a textarea, the checked state of a check box,
etc.
In other words, you would use simple getter and setter methods instead
of properties. It is the simplest solution. (And I believe, it is
non-pythonic, but that is just an opinion.)

I would like to hear other opinions.
Peter Otten
2016-09-11 15:28:29 UTC
Permalink
Post by Nagy László Zsolt
Post by Chris Angelico
Yes, I believe it does. (Others may disagree. This is a design
question and very much a matter of style, not hard fact.) I would have
an explicit action "set_content" which will set the value of an input
field, the inner text of a textarea, the checked state of a check box,
etc.
In other words, you would use simple getter and setter methods instead
of properties. It is the simplest solution. (And I believe, it is
non-pythonic, but that is just an opinion.)
I would like to hear other opinions.
Disregarding potential implementation obstacles I think it would be clean
and clear if you could access a property foo in a base class with

super().foo

and set it with

super().foo = value
... @property
... def foo(self): return "foo"
...
... @property
... def foo(self): return super().foo.upper()
...
Post by Nagy László Zsolt
Post by Chris Angelico
A().foo
'foo'
Post by Nagy László Zsolt
Post by Chris Angelico
B().foo
'FOO'
Ethan Furman
2016-09-11 15:42:19 UTC
Permalink
Post by Peter Otten
Post by Nagy László Zsolt
Post by Chris Angelico
Yes, I believe it does. (Others may disagree. This is a design
question and very much a matter of style, not hard fact.) I would have
an explicit action "set_content" which will set the value of an input
field, the inner text of a textarea, the checked state of a check box,
etc.
In other words, you would use simple getter and setter methods instead
of properties. It is the simplest solution. (And I believe, it is
non-pythonic, but that is just an opinion.)
I would like to hear other opinions.
Disregarding potential implementation obstacles I think it would be clean
and clear if you could access a property foo in a base class with
super().foo
and set it with
super().foo = value
... def foo(self): return "foo"
...
... def foo(self): return super().foo.upper()
...
Post by Nagy László Zsolt
Post by Chris Angelico
A().foo
'foo'
Post by Nagy László Zsolt
Post by Chris Angelico
B().foo
'FOO'
Yes, the get part works. The set part is a pain, and a bit ugly:

super(B, B).foo.__set__(self, value)

There is an issue for this on the tracker: http://bugs.python.org/issue14965

--
~Ethan~
Nagy László Zsolt
2016-09-11 18:26:05 UTC
Permalink
Post by Ethan Furman
super(B, B).foo.__set__(self, value)
http://bugs.python.org/issue14965
Thank you Ethan!

The superprop pure Python implementation is very promising. (
http://bugs.python.org/file37546 ) I can use that instead of my
"property virtualizers" until Python built in support becomes available. :-)
Loading...