Python black magic @ property annotator usage tips, python @ property
@ What is the use of property? On the surface, a method is accessed using attributes.
The Code is the clearest.
class Circle(object): def __init__(self, radius): self.radius = radius @property def area(self): return 3.14 * self.radius ** 2 c = Circle(4) print c.radius print c.area
As you can see, although area is defined as a method, after adding @ property, you can directly access area as a property.
Now the question is: (which is not the best excavator technology?) Every time c. area is called, it will be calculated once, which is a waste of cpu resources. How can we calculate it only once? This is lazy property.
class lazy(object): def __init__(self, func): self.func = func def __get__(self, instance, cls): val = self.func(instance) setattr(instance, self.func.__name__, val) return val class Circle(object): def __init__(self, radius): self.radius = radius @lazy def area(self): print 'evalute' return 3.14 * self.radius ** 2 c = Circle(4) print c.radius print c.area print c.area print c.area
As you can see, 'evalute' is output only once. If you read the previous blog posts, you should have a good understanding of the @ lazy mechanism.
Here, the lazy class has the _ get _ method, which indicates that it is a descriptor and runs c. when area is used, c. _ dict _ is found. If it is not found, the class space will be searched. In the class Circle, there is an area () method, so it will be intercepted by _ get.
In _ get _, call the area () method of the instance to calculate the result, and dynamically add an attribute with the same name to the instance to assign the result to it, that is, add it to c. _ dict.
When executing c. area again, go to c. _ dict _ to find it. Because it already exists, it will not go through the area () method and _ get.
Notes
Note the following code scenarios:
Code snippet 1:
Python2.6 code
class Parrot(object): def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage if __name__ == "__main__": # instance p = Parrot() # similarly invoke "getter" via @property print p.voltage # update, similarly invoke "setter" p.voltage = 12
Code snippet 2:
Python2.6 code
class Parrot: def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage if __name__ == "__main__": # instance p = Parrot() # similarly invoke "getter" via @property print p.voltage # update, similarly invoke "setter" p.voltage = 12
The difference between code 1 and Code 2 is that
class Parrot(object):
Run the test respectively in python2.6.
Segment 1: An expected error message AttributeError: can't set attribute will be displayed.
Segment 2: run properly
For more information, see python2.6. @ property provides a ready-only property. The above Code does not provide the corresponding @ voltage. setter, it is reasonable to say that part 2 code will prompt a running error. In python2.6, we can find the following information:
BIF:
Property ([fget [, fset [, fdel [, doc])
Return a property attribute for new-style classes (classes that derive from object ).
Originally in python2.6, the built-in object type is not the default base class. If the class is not explicitly defined (code segment 2), we define the Parrot (code segment 2) will not inherit the object
The object class provides the @ property function we need. In this document, we can find the following information:
New-style class
Any class which inherits from object. this includes des all built-in types like list and dict. only new-style classes can use Python's newer, versatile features like _ slots __, descriptors, properties, and _ getattribute __().
At the same time, we can use the following methods to verify
Python code 2.6
class A: pass >>type(A) <type 'classobj'>
Python code 2.6
class A(object): pass >>type(A) <type 'type'>
From the returned <type 'classobj '> and <type 'type'>, we can see that <type 'type'> is the object type we need (python 3.0 uses the object class as the default base class, therefore, <type 'type'> is returned)
In order to consider the compatibility of the python version of the Code during the transition period, I think objects should be explicitly defined when class files are to be defined. As a good habit
The final code is as follows:
class Parrot(object): def __init__(self): self._voltage = 100000 @property def voltage(self): """Get the current voltage.""" return self._voltage @voltage.setter def voltage(self, new_value): self._voltage = new_value if __name__ == "__main__": # instance p = Parrot() # similarly invoke "getter" via @property print p.voltage # update, similarly invoke "setter" p.voltage = 12
In addition, @ property is added in 2.6 and 3.0. This function is not available in 2.5.