@lru_cache: Speed Up Your Programs by Cachin
This decorator can be used to cache the results of a function, so that subsequent calls to the function with the same arguments will not be executed again.
Example:
from functools import lru_cache
import time
@lru_cache(maxsize=None)
def fibonacci(n):
if n < 2:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
start_time = time.perf_counter()
print(f"{fibonacci(100) = }")
end_time = time.perf_counter()
print(f"The execution time: {end_time - start_time:.8f} seconds")
# fibonacci(100) = 354224848179261915075
# The execution time: 0.00061948 seconds
@total_ordering: A Class Decorator That Fills In Missing Ordering Methods
The @total_ordering decorator from the functools module is used to generate the missing comparison methods for a Python class based on the ones that are defined.
Example:
from functools import total_ordering
@total_ordering
class Student:
def __init__(self, name, grade):
self.name = name
self.grade = grade
def __eq__(self, other):
return self.grade == other.grade
def __lt__(self, other):
return self.grade < other.grade
student1 = Student("Alice", 85)
student2 = Student("Bob", 75)
student3 = Student("Charlie", 85)
print(student1 < student2) # False
print(student1 > student2) # True
print(student1 == student3) # True
print(student1 <= student3) # True
print(student3 >= student2) # True
@contextmanager: Make a Customized Context Manager
Sometimes, we need to define a customized context manager for some special requirements. In this case, the @contextmanager decorator is our friend.
Example:
from contextlib import contextmanager
@contextmanager
def file_manager(filename, mode):
print("The file is opening...")
file = open(filename,mode)
yield file
print("The file is closing...")
file.close()
with file_manager('test.txt', 'w') as f:
f.write('Yang is writing!')
# The file is opening...
# The file is closing...
@property: Setting Up Getters and Setters for Python Classes
For each instance variable of a class, a getter method returns its value while a setter method sets or updates its value. Given this, getters and setters are also known as accessors and mutators, respectively.
Example:
class Student:
def __init__(self):
self._score = 0
@property
def score(self):
return self._score
@score.setter
def score(self, s):
if 0 <= s <= 100:
self._score = s
else:
raise ValueError('The score must be between 0 ~ 100!')
Yang = Student()
Yang.score=99
print(Yang.score)
# 99
Yang.score = 999
# ValueError: The score must be between 0 ~ 100!
@cached_property: Cache the Result of a Method as an Attribute
Python 3.8 introduced a new powerful decorator to the functool module — @cached_property. It can transform a method of a class into a property whose value is computed once and then cached as a normal attribute for the life of the instance.
Example:
from functools import cached_property
class Circle:
def __init__(self, radius):
self.radius = radius
@cached_property
def area(self):
return 3.14 * self.radius ** 2
circle = Circle(10)
print(circle.area)
# prints 314.0
print(circle.area)
# returns the cached result (314.0) directly
@classmethod: Define Class Methods in a Python Class
- Instance methods: methods that are bound to an instance. They can access and modify the instance data. An instance method is called on an instance of the class, and it can access the instance data through the self parameter.
- Class methods: methods that are bound to the class. They can’t modify the instance data. A class method is called on the class itself, and it receives the class as the first parameter, which is conventionally named cls.
- Static methods: methods that are not bound to the instance or the class.
Example:
class Circle:
def __init__(self, radius):
self.radius = radius
@classmethod
def from_diameter(cls, diameter):
return cls(diameter / 2)
@property
def diameter(self):
return self.radius * 2
@diameter.setter
def diameter(self, diameter):
self.radius = diameter / 2
c = Circle.from_diameter(8)
print(c.radius) # 4.0
print(c.diameter) # 8.0
@staticmethod: Define Static Methods in a Python Class
Static methods are commonly used in utility classes that perform a group of related tasks, such as mathematical calculations. By organizing related functions into static methods within a class, our code will become more organized and easier to understand.
Example:
class Student:
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
self.nickname = None
def set_nickname(self, name):
self.nickname = name
@staticmethod
def suitable_age(age):
return 6 <= age <= 70
print(Student.suitable_age(99)) # False
print(Student.suitable_age(27)) # True
print(Student('yang', 'zhou').suitable_age(27)) # True
@dataclass: Define Special Classes With Less Code
The @dataclass decorator (introduced in Python 3.7) can automatically generate several special methods for a class, such as init, repr, eq, lt, and so on.
Example:
from dataclasses import dataclass
@dataclass
class Point:
x: float
y: float
point = Point(1.0, 2.0)
print(point)
# Point(x=1.0, y=2.0)
@atexit.register: Register a Function To Be Executed Upon Normal Program Termination
The @register decorator from the atexit module can allow us to execute a function when the Python interpreter is exiting.
Example:
import atexit
@atexit.register
def goodbye():
print("Bye bye!")
print("Hello Paul!")
# Hello Paul!
# Bye bye!