Articles Catalogue
prototype
class property(fget=None, fset=None, fdel=None, doc=None)
It returns an attribute.
For example:
class C: @property def x(self): return None print(type(x))
You can see that the result of printing is:
<class 'property'>
That is to say, the returned x is actually a class object, remember, it is not an instance of a class, it is itself a class, called property. This class has setter and deleter methods, which will be used below.
That is to say, property is actually a class. When initializing, the four parameters above can be given. The first three parameters are all parameters of the receiving function type. They are used to get the value of the attribute, set the value of the attribute, and delete the attribute respectively. The last doc is used to set the docstring of the attribute.
Look at the difference between it and class attributes:
class C: 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.") y = 1 c = C() print(C.x) print(C.y) print(c.x) print(c.y)
The result of printing is:
<property object at 0x000002789820F458> 1 None 1
That is to say, x is also a class attribute, but if you access it through instance C of C, you will access the corresponding getx setx delx and other methods.
Let's look at an example:
class C: def __init__(self): self._x = None def getx(self): print('getter') return self._x def setx(self, value): print('setter') self._x = value def delx(self): print('deleter') del self._x x = property(getx, setx, delx, "I'm the 'x' property.") c = C() print(c.x) c.x = 1 print(c.x) del c.x # print(c.x) #Because del is used above, errors will be reported here
The final print result is:
getter None setter getter 1 deleter
It's very similar to MyProperty below (if you're familiar with it). Descriptor The concept is well understood below.
class MyProperty: def __init__(self, getter, setter, deleter, docstr): self.getter = getter self.setter = setter self.deleter = deleter self.docstr = docstr def __get__(self, instance, owner): return self.getter(instance) def __set__(self, instance, value): self.setter(instance, value) class C: 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 = MyProperty(getx, setx, delx, "I'm the 'x' property.") c = C() print(c.x) c.x = 1 print(c.x)
Read-only property
If we want an attribute to be readable and not modified, we can use the following ways:
class C: def __init__(self): self._x = 1 @property def x(self): return self._x c = C() print(c.x) # c.x = 1 # Because it's set to read-only, modifications here will cause errors
The final result is:
1
Similarly, we can write a replacement (of course, many of the substitutions in this article, because they are examples, do not take into account all situations, only code the current situation used):
class MyProperty: def __init__(self, getter=None, setter=None, deleter=None, docstr=None): self.getter = getter self.setter = setter self.deleter = deleter self.docstr = docstr def __get__(self, instance, owner): return self.getter(instance) def __set__(self, instance, value): if not self.setter: raise AttributeError("can't set attribute") class C: def __init__(self): self._x = 1 @MyProperty def x(self): return self._x c = C() print(c.x) c.x = 1
Result:
1
Finally, an AttributeError: can't set attribute exception is thrown.
More
After using @property as above, the attributes become read-only. If you want to become writable and deletable, you can use the following way:
class C: def __init__(self): self._x = 1 @property def x(self): return self._x @x.setter def x(self, value): self._x = value @x.deleter def x(self): del self._x c = C() print(c.x) c.x = 2 print(c.x) del c.x # print(c.x) # Throw an exception here
Result:
1 2