python: why getter & setter? how can I set attribute quickly? [duplicate] - python

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the benefit to using a ‘get function’ for a python class?
I just started to read Python, but I wonder why does Python need setter and getter at all? it already have object variables which act like property
Consider
class C(object):
def _init_(self):
self._x = None
def get_x(self):
return self._x
def set_x(self, value):
self._x = valu
x = property(get_x, set_x)
Can we just use C.x = "value" to do what we want to do here? what is the benefit of property?
BTW, creating property/setter/getter in this way is cumbersome to me, is there any way to simplify this? like
class C()
has_attributes("x", "y", "z")

You can use a property to obtain what you want:
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
Then you can access the attribute with the usual attribute syntax:
c = C()
c.x = 10 #calls the setter
print(c.x) #calls the getter
There are some reasons to use a property instead of a plain data attribute:
You can document the attribute
You can control the access to the attribute, either by making it read-only or by checking the type/value being set
You do not break backwards compatibility: if something was a plain instance attribute and then you decide to transform it into a property the code that worked with the attribute will still work. If you used get/set explicit methods all the code that used the old API would have to change
It's more readable then using explicit get/set methods.

Use plain attributes:
class C(object):
def __init__(self):
self.x = None
Later, when and if it would be necessary, x can be changed to a property. The beauty of "#property" it that is allows developer not to use getters, setters and "#property".

class C(object):
def _init_(self):
self._x = None
def get_x(self):
return self._x
def set_x(self, value):
self._x = value
x = property(get_x, set_x)
now you can use c.x = "foo" with the set and gets, transparently.
The purpose of a set and getter is don't expose the class internals.
Imagine that in the future
self._x
changes to
sql.save(id(self), value)
and get_x to:
value= sql.sql(id(self))
return convertFromDbFormatToExpectedApiFormat(value)
You will only have to change the code of getter and setters in only that class, not change
all the classes that communicates with it.
class C(object):
def _init_(self):
self.sql = DDBB()
def get_x(self):
dbregistry = self.sql.fetch(id(self))
return convertFromDbFormatToExpectedApiFormat(dbregistry)
def set_x(self, value):
self.sql.save(id(self), value)
x = property(get_x, set_x)

Related

Class property returning property object

Before this is flagged as a duplicate, I know this question has been answered before, but the solutions provided there don't seem to apply to my case. I'm trying to programmatically set class properties. I know I can use property for that, so I thought about doing this:
class Foo:
def __init__(self, x):
self._x = x
def getx(): return self._x
def setx(y): self._x = y
self.x = property(fget=getx, fset=setx)
However, when I run this interactively, I get:
>>> f = Foo(42)
>>> f.x
<property object at 0x0000000>
>>> f._x
42
>>> f.x = 1
>>> f.x
1
Is there any way to solve this?
Edit:
I feel I may have left out too much, so here's what I am actually trying to reach. I have a class with a class variable called config, which contains configuration values to set as properties. The class should be subclassed to implement the config variable:
class _Base:
config = ()
def __init__(self, obj, **kwargs):
self._obj = obj()
for kwarg in kwargs:
# Whatever magic happens here to make these properties
# Sample implementation
class Bar(_Base):
config = (
"x",
"y"
)
def __init__(self, obj, x, y):
super().__init__(obj, x=x, y=y)
Which now allows for manipulation:
>>> b = Bar(x=3, y=4)
>>> b.x
3
>>> # Etc.
I'm trying to keep this as DRY as possible because I have to subclass _Base a lot.
property objects are descriptors, and descriptors are only invoked when defined on the class or metaclass. You can't put them directly on an instance; the __getattribute__ implementation for classes simply don't invoke the binding behaviour needed.
You need to put the property on the class, not on each instance:
class Foo:
def __init__(self, x):
self._x = x
#property
def x(self): return self._x
#x.setter
def x(self, y): self._x = y
If you have to have a property that only works on some instances, you'll have to alter your getter and setter methods to vary behaviour (like raise an AttributeError for when the state of the instance is such that the attribute should 'not exist').
class Bar:
def __init__(self, has_x_attribute=False):
self._has_x_attribute = has_x_attribute
self._x = None
#property
def x(self):
if not self._has_x_attribute:
raise AttributeError('x')
return self._x
#x.setter
def x(self, y):
if not self._has_x_attribute:
raise AttributeError('x')
self._x = y
The property object still exists and is bound, but behaves as if the attribute does not exist when a flag is set to false.

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

Do each instance variable need a new property get/set method?

I've read several tutorials, articles and questions here on stackoverflow, including the python doc, but all of them are using a single instance variable in their examples, making it difficult to see how python properties would work if you have more than one.
At first i thought the property function was created to be able to set or get any property so you could only create one get and one set method and then any number of instance variables which would use these, but this doesnt seem to be the case(?)
If I have the following code (taken straight from the official doc on property()):
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
You have one method "getx" and one method "setx" in addition to the deleter method "delx". What if i also need a couple of more instances variables like y and z, do i then need to write the following code:
class C(object):
def __init__(self, x, y, z):
self._x = None
self._y = 2
self._z = 4
def getx(self):
return self._x
def gety(self):
return self._y
def getz(self):
return self._z
def setx(self, value):
self._x = value
def sety(self, value):
self._y = value
def setz(self, value):
self._z = value
def delx(self):
del self._x
def dely(self):
del self._y
def delz(self):
del self._z
x = property(getx, setx, delx, "I'm the 'x' property.")
y = property(gety, sety, dely, "I'm the 'y' property.")
z = property(getz, setz, delz, "I'm the 'z' property.")
The above code looks a lot like java setters/getters, and the reason for using property in python seems to be exactly to avoid this, so are you meant to be using some sort og general getter/setter instead ?
Please dont bash me with tons of -1, im just trying to understand this and i have read quite a bit to try to avoid posting this people often get annoyed it seems when people arent a master in python.
The getters and setters in your example are useless, just skip them. All you need is:
class C(object):
def __init__(self, x, y, z):
self.x = None
self.y = 2
self.z = 4
Getters and setters are only needed if you want to do something unusual. Merely getting an attribute and setting an attribute can be done simply with an attribute.

Python overriding setter to an attribute with no setter?

I have a class A made by someone else, that I cannot edit:
class A:
def __init__(self, x):
self.x = x
Now I'm trying to inherit my own class B from A, and have x as a property instead of an attribute.
Is this possible?
I already tried:
class B(A):
def __init__(self, x):
super().__init__(x)
#property
def x(self):
return super().x
#x.setter
def x(self, x):
super().x = x
print(x) # my stuff goes here
But as I expected, it's not possible: AttributeError: 'super' object has no attribute 'x'
Is there any other method, some workaroud maybe?
No, you cannot use super() for anything other than class attributes; x is an instance attribute, and there is no inheritance mechanism for attributes.
Instance attributes live in a single namespace; there is no 'parent instance' attribute namespace.
You can still reach the attribute in the instance __dict__ object:
class B(A):
#property
def x(self):
return self.__dict__['x']
#x.setter
def x(self, x):
self.__dict__['x'] = x
print(x) # my stuff goes here
A property is a data descriptor, meaning that it is looked up before the instance attributes are consulted (see the descriptor howto), but you can still access it directly.

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

Categories

Resources