How does python builtin #property receives the overloaded setter function ? - python

When defining a builtin python property using the #property, how does the property object differentiates the setter from the getter method, provided that they are overloaded (have the same name)?
class A:
def __init__(self):
self._x = 12
#property
def x(self) -> int:
return self._x
#notifiable # strangely this stacks on both setter and getter
#x.setter
def x(self, val: int):
self._x = val
If I define a custom property decorator, say:
class my_property:
def __init__(self, getter):
print("__init__ getter %s:" % getter)
def setter(self, setter: FunctionType):
print("setter: %s" % setter)
class B:
def __init__(self):
self._val = 44
#my_property
def x(self):
return self._val
#x.setter
def x(self, val):
self._val = val
Executing the code results in the following output
__init__ getter <function B.x at 0x7ff80c5e1620>:
setter: <function B.x at 0x7ff80c5e1620>
Both the getter and the setter funtions passed to the decorator are the same funtion, but they should be different functions.
If I use the annotation like this:
class C:
def __init__(self):
self._val = 44
#my_property
def x(self):
return self._val
#x.setter
def set_x(self, val):
self._val = val
A different function is printed, as expected.
__init__ getter <function C.x at 0x7f529132c6a8>:
setter: <function C.set_x at 0x7f529132c6a8>
How does python solves this issue with the builtin #property? Is the decorator treated differently from user decorators ?

The reason you're seeing what you're seeing here is because you don't keep a reference to the getter anywhere. This means that once the __init__ method ends, there's no more reference to the first B.x, (i.e. the refcount is zero), so the function is released. Since the original getter function has been released, Python is free to reuse the exact same memory address for another object/function, which is what happens in this case.
If you modify my_property to keep a reference to the original getter method as such:
class my_property:
def __init__(self, getter):
print("__init__ getter %s:" % getter)
self.getter = getter
def setter(self, setter: FunctionType):
print("setter: %s" % setter)
you'll see that the function name (B.x) is still the same (which is ok, as python doesn't use the function name to uniquely identify a function), however the memory address of the two functions are different:
__init__ getter <function B.x at 0x7f9870d60048>
setter: <function B.x at 0x7f9870d600d0>
Is the decorator treated differently from user decorators ?
No, property just a regular decorator. However, if you want to reimplement the property decorator, you'd probably be interested in the descriptor protocol (there's a pure python reimplementation of #property in that page).

Related

Why is Class property.setter not a case of method overloading?

Method overloading is not possible in Python!
Can you please explain why Properties.setter in Python is not a case of method overloading?
class newOne():
def __init__(self):
self.__x = 0
#property
def val(self):
return self.__x
#val.setter
def val(self,value):
self.__x = value
In the above code, I have two methods with the same name 'val' (but different set of args) and both behave differently.
It's not method overloading because there aren't two methods with different signatures that can be called. If it was method overloading, you could do something like this:
obj = newOne()
print(obj.val())
obj.val(5)
But that doesn't work, because val is a property and not an overloaded method.
So what's going on there? Why are we defining two methods with the same name, and what happens to them, if not overloading?
The magic happens in the decorators. As a prerequisite, you have to know that
#deco
def func(...):
...
is equivalent to
def func(...):
...
func = deco(func)
So, the first thing that happens is that the #property decorator turns your getter function into a property with that function as its getter function:
class newOne:
#property
def val(self):
return self.__x
print(newOne.val)
print(newOne.val.fget)
# output:
# <property object at 0x002B1F00>
# <function newOne.val at 0x0052EAE0>
After this, the #val.setter decorator creates a new property with a getter and setter function:
class newOne:
#property
def val(self):
return self.__x
#val.setter
def val(self, value):
self.__x = value
print(newOne.val)
print(newOne.val.fget)
print(newOne.val.fset)
# output:
# <property object at 0x0221B7B0>
# <function newOne.val at 0x0226EB70>
# <function newOne.val at 0x0226EAE0>
(The getter and setter functions have the same name because they were both defined as def val(...), but they're still different functions. That's why they have different ids.)
So in the end you have a val property with a getter and a setter function. You do not have an overloaded method.
For details about how properties work and how the getter and setter functions are called, see the descriptor documentation.
First, the #property decorator creates a descriptor named val and sets it aside to add to the class once it is defined. Then, the #val.setter decorated takes its function and simplyeffectively adds a reference to it to the val descriptor.
Your code is roughly equivalent to
d = {}
def __init__(self):
self.__x = 0
d['__init__'] = __init__
def val(self):
return self.__x
d['val'] = property(val)
def val(self, value):
self.__x = value
# Not d['val'].__set__ = val, as previously stated
d['val'] = property(fget=d['val'], fset=val)
newOne = type('newOne', (object,), d)
# These are all "local" to, or part of the implementation of,
# the class statement, so they don't stick around in the current
# namespace.
del __init__, val, d # These are all "local" to or part of the imple

Overload a property setter in Python [duplicate]

So, I'm trying to figure out the best (most elegant with the least amount of code) way to allow overriding specific functions of a property (e.g., just the getter, just the setter, etc.) in python. I'm a fan of the following way of doing properties, due to the fact that all of their methods are encapsulated in the same indented block of code (it's easier to see where the functions dealing with one property stop and the functions dealing with the next begin):
#apply
def foo():
"""A foobar"""
def fget(self):
return self._foo
def fset(self, val):
self._foo = val
return property(**locals())
However, if I want to inherit from a class that defines properties in this manner, and then, say, override the foo setter function, it seems tricky. I've done some searching and most of the answers I've found have been to define separate functions in the base class (e.g. getFoo and setFoo), explicitly create a property definition from them (e.g. foo = property(lambda x: x.getFoo(), lambda x, y: x.setFoo(y), lambda x: x.delFoo())), and then override getFoo, setFoo, and delFoo as needed.
I dislike this solution because it means I have to define lambas for every single property, and then write out each function call (when before I could have just done property(**locals())). I also don't get the encapsulation that I had originally.
Ideally, what I would like to be able to do would be something like this:
class A(object):
def __init__(self):
self.foo = 8
#apply
def foo():
"""A foobar"""
def fget(self):
return self._foo
def fset(self, val):
self._foo = val
return property(**locals())
class ATimesTwo(A):
#some_decorator
def foo():
def fset(self, val):
self._foo = val * 2
return something
And then the output would look something like:
>>> a = A()
>>> a.foo
8
>>> b = ATimesTwo()
>>> b.foo
16
Basically, ATimesTwo inherits the getter function from A but overrides the setter function. Does anybody know of a way to do this (in a manner that looks similar to the example above)? What function would the some_decorator look like, and what should the foo function return?
The Python docs on the property decorator suggest the following idiom:
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
#x.deleter
def x(self):
del self._x
And then subclasses can override a single setter/getter like this:
class C2(C):
#C.x.getter
def x(self):
return self._x * -1
This is a little warty because overriding multiple methods seems to require you to do something like:
class C3(C):
#C.x.getter
def x(self):
return self._x * -1
# C3 now has an x property with a modified getter
# so modify its setter rather than C.x's setter.
#x.setter
def x(self, value):
self._x = value * 2
Of course at the point that you're overriding getter, setter, and deleter you can probably just redefine the property for C3.
I'm sure you've heard this before, but apply has been deprecated for eight years, since Python 2.3. Don't use it. Your use of locals() is also contrary to the Zen of Python -- explicit is better than implicit. If you really like the increased indentation, there is no need to create a throwaway object, just do
if True:
#property
def foo(self):
return self._foo
#foo.setter
def foo(self, val):
self._foo = val
Which doesn't abuse locals, use apply, require creation of an extra object, or need a line afterwards with foo = foo() making it harder to see the end of the block. It works just as well for your old-fashioned way of using property -- just do foo = property(fget, fset) as normal.
If you want to override a property in an arbitrary subclass, you can use a recipe like this.
If the subclass knows where the property was defined, just do:
class ATimesTwo(A):
#A.foo.setter
def foo(self, val):
self._foo = val * 2
The answer of stderr satisfies most use cases.
I'd like to add a solution for the case where you want to extend a getter, setter and/or deleter. Two ways to do this are:
1. Subclass property
First way to do this is by subclassing the builtin property and adding decorators that are versions of getter, setter and/or deleter that extend the current get, set and delete callbacks
Example for a property that supports appending methods to the set-functions:
class ExtendableProperty(property):
def append_setter(self, fset):
# Create a wrapper around the new fset that also calls the current fset
_old_fset = self.fset
def _appended_setter(obj, value):
_old_fset(obj, value)
fset(obj, value)
# Use that wrapper as setter instead of only the new fset
return self.setter(_appended_setter)
Usage is the same as for normal properties, only now it is possible to add methods to the property setters:
class A(object):
#ExtendableProperty
def prop(self):
return self._prop
#prop.setter
def prop(self, v):
self._prop = v
class B(A):
#A.prop.append_setter
def prop(self, v):
print('Set', v)
>>> a = A()
>>> a.prop = 1
>>> a.prop
1
>>> b = B()
>>> b.prop = 1
Set 1
>>> b.prop
1
2. Overwrite getter, setter and/or deleter
Use a normal property, overwrite the getter, setter or deleter and then add calls to the fget, fset or fdel in the property of the parent class.
Example for the type of property as in example 1:
class A(object):
#property
def prop(self):
return self._prop
#prop.setter
def prop(self, v):
self._prop = v
class B(A):
#A.prop.setter
def prop(self, v):
A.prop.fset(self, v) # This is the call to the original set method
print('Set {}'.format(v))
I think the first option looks nicer because the call to the super property's fset is not necessary

Overriding properties in python

So, I'm trying to figure out the best (most elegant with the least amount of code) way to allow overriding specific functions of a property (e.g., just the getter, just the setter, etc.) in python. I'm a fan of the following way of doing properties, due to the fact that all of their methods are encapsulated in the same indented block of code (it's easier to see where the functions dealing with one property stop and the functions dealing with the next begin):
#apply
def foo():
"""A foobar"""
def fget(self):
return self._foo
def fset(self, val):
self._foo = val
return property(**locals())
However, if I want to inherit from a class that defines properties in this manner, and then, say, override the foo setter function, it seems tricky. I've done some searching and most of the answers I've found have been to define separate functions in the base class (e.g. getFoo and setFoo), explicitly create a property definition from them (e.g. foo = property(lambda x: x.getFoo(), lambda x, y: x.setFoo(y), lambda x: x.delFoo())), and then override getFoo, setFoo, and delFoo as needed.
I dislike this solution because it means I have to define lambas for every single property, and then write out each function call (when before I could have just done property(**locals())). I also don't get the encapsulation that I had originally.
Ideally, what I would like to be able to do would be something like this:
class A(object):
def __init__(self):
self.foo = 8
#apply
def foo():
"""A foobar"""
def fget(self):
return self._foo
def fset(self, val):
self._foo = val
return property(**locals())
class ATimesTwo(A):
#some_decorator
def foo():
def fset(self, val):
self._foo = val * 2
return something
And then the output would look something like:
>>> a = A()
>>> a.foo
8
>>> b = ATimesTwo()
>>> b.foo
16
Basically, ATimesTwo inherits the getter function from A but overrides the setter function. Does anybody know of a way to do this (in a manner that looks similar to the example above)? What function would the some_decorator look like, and what should the foo function return?
The Python docs on the property decorator suggest the following idiom:
class C(object):
def __init__(self):
self._x = None
#property
def x(self):
return self._x
#x.setter
def x(self, value):
self._x = value
#x.deleter
def x(self):
del self._x
And then subclasses can override a single setter/getter like this:
class C2(C):
#C.x.getter
def x(self):
return self._x * -1
This is a little warty because overriding multiple methods seems to require you to do something like:
class C3(C):
#C.x.getter
def x(self):
return self._x * -1
# C3 now has an x property with a modified getter
# so modify its setter rather than C.x's setter.
#x.setter
def x(self, value):
self._x = value * 2
Of course at the point that you're overriding getter, setter, and deleter you can probably just redefine the property for C3.
I'm sure you've heard this before, but apply has been deprecated for eight years, since Python 2.3. Don't use it. Your use of locals() is also contrary to the Zen of Python -- explicit is better than implicit. If you really like the increased indentation, there is no need to create a throwaway object, just do
if True:
#property
def foo(self):
return self._foo
#foo.setter
def foo(self, val):
self._foo = val
Which doesn't abuse locals, use apply, require creation of an extra object, or need a line afterwards with foo = foo() making it harder to see the end of the block. It works just as well for your old-fashioned way of using property -- just do foo = property(fget, fset) as normal.
If you want to override a property in an arbitrary subclass, you can use a recipe like this.
If the subclass knows where the property was defined, just do:
class ATimesTwo(A):
#A.foo.setter
def foo(self, val):
self._foo = val * 2
The answer of stderr satisfies most use cases.
I'd like to add a solution for the case where you want to extend a getter, setter and/or deleter. Two ways to do this are:
1. Subclass property
First way to do this is by subclassing the builtin property and adding decorators that are versions of getter, setter and/or deleter that extend the current get, set and delete callbacks
Example for a property that supports appending methods to the set-functions:
class ExtendableProperty(property):
def append_setter(self, fset):
# Create a wrapper around the new fset that also calls the current fset
_old_fset = self.fset
def _appended_setter(obj, value):
_old_fset(obj, value)
fset(obj, value)
# Use that wrapper as setter instead of only the new fset
return self.setter(_appended_setter)
Usage is the same as for normal properties, only now it is possible to add methods to the property setters:
class A(object):
#ExtendableProperty
def prop(self):
return self._prop
#prop.setter
def prop(self, v):
self._prop = v
class B(A):
#A.prop.append_setter
def prop(self, v):
print('Set', v)
>>> a = A()
>>> a.prop = 1
>>> a.prop
1
>>> b = B()
>>> b.prop = 1
Set 1
>>> b.prop
1
2. Overwrite getter, setter and/or deleter
Use a normal property, overwrite the getter, setter or deleter and then add calls to the fget, fset or fdel in the property of the parent class.
Example for the type of property as in example 1:
class A(object):
#property
def prop(self):
return self._prop
#prop.setter
def prop(self, v):
self._prop = v
class B(A):
#A.prop.setter
def prop(self, v):
A.prop.fset(self, v) # This is the call to the original set method
print('Set {}'.format(v))
I think the first option looks nicer because the call to the super property's fset is not necessary

Custom property with setter

I am looking for a pure Python implementation of the property builtin to understand how initialization works. I have found many that deal with the descriptor interface (__get__, __set__) but none describing the setter or deleter methods. Is this definition in the Python Decorator Library (roughly) the way it is implemented?
Property is a simple, straightforward descriptor. Descriptor protocol consists of three methods: __get__, __set__ and __delete__. Property for each of those operations simply calls user-provided functions.
class my_property(object):
def __init__(self, getter, setter, deleter):
self.getter = getter
self.setter = setter
self.deleter = deleter
def __get__(self, instance, owner):
return self.getter(instance)
def __set__(self, instance, value):
self.setter(instance, value)
def __delete__(self, instance):
self.deleter(instance)
class Foo(object):
def __init__(self):
self._x = 42
def get_x(self):
print 'getter'
return self._x
def set_x(self, value):
print 'setter'
self._x = value
def del_x(self):
print 'deleter'
del self._x
x = my_property(get_x, set_x, del_x)
obj = Foo()
print obj.x
obj.x = 69
del obj.x
print obj.x
As a comment: there is a simple way to add property to a Python list object. Warp in a class.
>>> class Foo(list): pass
>>> l = Foo([1,2,3])
>>> l.foo = 'bar'
>>> l
[1, 2, 3]

How to call a property of the base class if this property is being overwritten in the derived class?

I'm changing some classes of mine from an extensive use of getters and setters to a more pythonic use of properties.
But now I'm stuck because some of my previous getters or setters would call the corresponding method of the base class, and then perform something else. But how can this be accomplished with properties? How to call the property getter or setter in the parent class?
Of course just calling the attribute itself gives infinite recursion.
class Foo(object):
#property
def bar(self):
return 5
#bar.setter
def bar(self, a):
print a
class FooBar(Foo):
#property
def bar(self):
# return the same value
# as in the base class
return self.bar # --> recursion!
#bar.setter
def bar(self, c):
# perform the same action
# as in the base class
self.bar = c # --> recursion!
# then do something else
print 'something else'
fb = FooBar()
fb.bar = 7
You might think you could call the base class function which is called by property:
class FooBar(Foo):
#property
def bar(self):
# return the same value
# as in the base class
return Foo.bar(self)
Though this is the most obvious thing to try I think - it does not work because bar is a property, not a callable.
But a property is just an object, with a getter method to find the corresponding attribute:
class FooBar(Foo):
#property
def bar(self):
# return the same value
# as in the base class
return Foo.bar.fget(self)
super() should do the trick:
return super().bar
In Python 2.x you need to use the more verbose syntax:
return super(FooBar, self).bar
There is an alternative using super that does not require to explicitly reference the base class name.
Base class A:
class A(object):
def __init__(self):
self._prop = None
#property
def prop(self):
return self._prop
#prop.setter
def prop(self, value):
self._prop = value
class B(A):
# we want to extend prop here
pass
In B, accessing the property getter of the parent class A:
As others have already answered, it's:
super(B, self).prop
Or in Python 3:
super().prop
This returns the value returned by the getter of the property, not the getter itself but it's sufficient to extend the getter.
In B, accessing the property setter of the parent class A:
The best recommendation I've seen so far is the following:
A.prop.fset(self, value)
I believe this one is better:
super(B, self.__class__).prop.fset(self, value)
In this example both options are equivalent but using super has the advantage of being independent from the base classes of B. If B were to inherit from a C class also extending the property, you would not have to update B's code.
Full code of B extending A's property:
class B(A):
#property
def prop(self):
value = super(B, self).prop
# do something with / modify value here
return value
#prop.setter
def prop(self, value):
# do something with / modify value here
super(B, self.__class__).prop.fset(self, value)
One caveat:
Unless your property doesn't have a setter, you have to define both the setter and the getter in B even if you only change the behaviour of one of them.
try
#property
def bar:
return super(FooBar, self).bar
Although I'm not sure if python supports calling the base class property. A property is actually a callable object which is set up with the function specified and then replaces that name in the class. This could easily mean that there is no super function available.
You could always switch your syntax to use the property() function though:
class Foo(object):
def _getbar(self):
return 5
def _setbar(self, a):
print a
bar = property(_getbar, _setbar)
class FooBar(Foo):
def _getbar(self):
# return the same value
# as in the base class
return super(FooBar, self)._getbar()
def bar(self, c):
super(FooBar, self)._setbar(c)
print "Something else"
bar = property(_getbar, _setbar)
fb = FooBar()
fb.bar = 7
Some small improvements to Maxime's answer:
Using __class__ to avoid writing B. Note that self.__class__ is the runtime type of self, but __class__ without self is the name of the enclosing class definition. super() is a shorthand for super(__class__, self).
Using __set__ instead of fset. The latter is specific to propertys, but the former applies to all property-like objects (descriptors).
class B(A):
#property
def prop(self):
value = super().prop
# do something with / modify value here
return value
#prop.setter
def prop(self, value):
# do something with / modify value here
super(__class__, self.__class__).prop.__set__(self, value)
You can use the following template:
class Parent():
def __init__(self, value):
self.__prop1 = value
#getter
#property
def prop1(self):
return self.__prop1
#setter
#prop1.setter
def prop1(self, value):
self.__prop1 = value
#deleter
#prop1.deleter
def prop1(self):
del self.__prop1
class Child(Parent):
#getter
#property
def prop1(self):
return super(Child, Child).prop1.__get__(self)
#setter
#prop1.setter
def prop1(self, value):
super(Child, Child).prop1.__set__(self, value)
#deleter
#prop1.deleter
def prop1(self):
super(Child, Child).prop1.__delete__(self)
Note! All of the property methods must be redefined together. If do not want to redefine all methods, use the following template instead:
class Parent():
def __init__(self, value):
self.__prop1 = value
#getter
#property
def prop1(self):
return self.__prop1
#setter
#prop1.setter
def prop1(self, value):
self.__prop1 = value
#deleter
#prop1.deleter
def prop1(self):
del self.__prop1
class Child(Parent):
#getter
#Parent.prop1.getter
def prop1(self):
return super(Child, Child).prop1.__get__(self)
#setter
#Parent.prop1.setter
def prop1(self, value):
super(Child, Child).prop1.__set__(self, value)
#deleter
#Parent.prop1.deleter
def prop1(self):
super(Child, Child).prop1.__delete__(self)
class Base(object):
def method(self):
print "Base method was called"
class Derived(Base):
def method(self):
super(Derived,self).method()
print "Derived method was called"
d = Derived()
d.method()
(that is unless I am missing something from your explanation)

Categories

Resources