Python has several built-in decorators that are part of the language. The @property, @classmethod, and @staticmethod decorators are used to annotate methods of a class. The @property decorator transforms a method function into a descriptor. The @property decorator, when applied to a method function, changes the function into an attribute of the object. The property decorator, when applied to a method, also creates an additional pair of properties that can be used to create a setter and deleter property. We looked at this in Chapter 4, Attribute Access, Properties, and Descriptors.
The @classmethod and @staticmethod decorators transform a method function into a class-level function. The decorated method is now part of the class, not an object. In the case of a static method, there's no explicit reference to the class. With a class method, on the other hand, the class is the first argument of the method function. The following is an example of a class that includes @staticmethod and some @property definitions:
class Angle(float):
__slots__ = ("_degrees",)
@staticmethod
def from_radians(value: float) -> 'Angle':
return Angle(180 * value / math.pi)
def __init__(self, degrees: float) -> None:
self._degrees = degrees
@property
def radians(self) -> float:
return math.pi * self._degrees / 180
@property
def degrees(self) -> float:
return self._degrees
This class defines an Angle that can be represented in degrees or radians. The constructor expects degrees. However, we've also defined a from_radians() method function that emits an instance of the class. This function does not set values on an existing instance variable the way __init__() does; it creates a new instance of the class.
Additionally, we provide the degrees() and radians() method functions that have been decorated so that they are properties. Under the hood, these decorators create a descriptor so that accessing the attribute name degrees or radians will invoke the named method function. We can use the static method to create an instance and then use a property method to access a method function as follows:
>>> b = Angle.from_radians(.227) >>> round(b.degrees, 1)
13.0
The static method is similar to a function because it's not tied to the self instance variable. It has the advantage that it is syntactically bound to the class. Using Angle.from_radians can be more helpful than using a function named angle_from_radians. The use of these decorators ensures that implementation is handled correctly and consistently.
Now, let's see how to use standard library decorators.