Properties¶
https://en.wikipedia.org/wiki/Property_%28programming%29#Python
Attributes are clear and concise¶
One of the strengths of Python is lack of clutter.
In [5]: class C:
def __init__(self):
self.x = 5
In [6]: c = C()
In [7]: c.x
Out[7]: 5
In [8]: c.x = 8
In [9]: c.x
Out[9]: 8
And we want to maintain this clarity.
Getter and Setters¶
But what if you need to add behavior later?
- do some calculation
- check data validity
- keep things in sync
In [5]: class C:
...: def __init__(self):
...: self.x = 5
...: def get_x(self):
...: return self.x
...: def set_x(self, x):
...: self.x = x
...:
In [6]: c = C()
In [7]: c.get_x()
Out[7]: 5
In [8]: c.set_x(8)
In [9]: c.get_x()
Out[9]: 8
This is verbose – Java?
Properties¶
class C:
_x = None
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
In [28]: c = C()
In [30]: c.x = 5
In [31]: print(c.x)
5
Now the interface is like simple attribute access!
Decorators¶
What’s up with the “@” symbols?
Those are “decorations” it is a syntax for wrapping functions up with something special.
We will cover decorators in detail in another part of the program, but for now just copy the syntax.
@property
def x(self):
means: make a property called x with this as the “getter”.
@x.setter
def x(self, value):
means: make the “setter” of the ‘x’ property this new function
Read Only Attributes¶
You do not need to define a setter. If you don’t, you get a “read only” attribute:
In [11]: class D():
....: def __init__(self, x=5):
....: self._x = 5
....: @property
....: def getx(self):
....: """I am read only"""
....: return self._x
....:
In [12]: d = D()
In [13]: d.x
Out[13]: 5
In [14]: d.x = 6
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-14-c83386d97be3> in <module>()
----> 1 d.x = 6
AttributeError: can't set attribute
Deleters¶
If you want to do something special when a property is deleted, you can define a deleter as well:
In [11]: class D():
....: def __init__(self, x=5):
....: self._x = 5
....: @property
....: def x(self):
....: return self._x
....: @x.deleter
....: def x(self):
....: del self._x
If you leave this out, the property can’t be deleted, which is usually what you want.
[demo: properties_example.py
]