In Python, a decorator is essentially a Python function that allows other functions to add extra functionality without any code changes. The return value of the decorator is also a function object. It is often used in scenarios with aspect requirements, such as: log insertion, performance testing, transaction processing, caching, permission verification and other scenarios. Decorators are an excellent design to solve this kind of problem. With decorators, we can extract a lot of identical code that has nothing to do with the function itself and continue to reuse it. In a nutshell, the role of a decorator is to add extra functionality to an existing function or object .
The following is the simplest decorator that takes no arguments, and its input is a function name.
def debug(func):
def wrapper(funcarg):
print("Debug: " + func.__name__ + "...")
return func(funcarg)
return wrapper
@debug
def say_hello(name):
print("hello, " + name + "!")
if __name__ == '__main__':
say_hello("qinxue")
If you need to pass a lot of parameters, then change the parameters of the wrapper function inside to uniform parameters for any situation.
def debug(func):
def wrapper(*args, **kwargs):
print("Debug: " + func.__name__ + "...")
return func(*args, **kwargs)
return wrapper
@debug
def say_hello(name, age):
print("hello, " + name + "!" + "your age is: " + str(age))
if __name__ == '__main__':
say_hello("qinxue", 24)
Decorators with parameters , at this time, two layers of encapsulation are required. The first layer is a decorator function with parameters, and the second layer is a wrapper function that takes the function name as a parameter.
def logging(level):
def wrapper(func):
def inner_wrapper(*args, **kwargs):
print(level + ":" + "function: " + func.__name__ + "...")
return func(*args, **kwargs)
return inner_wrapper
return wrapper
@logging(level='INFO')
def say(something):
print("info: " + something)
@logging(level='DEBUG')
def do(something):
print("debug: " + something)
if __name__ == '__main__':
say("success!")
do("opps, something wrong!")
It can be understood that when a decorator with parameters is typed on a function, for example @logging(level='DEBUG')
, it is actually a function and will be executed immediately, as long as the result it returns is a decorator, then there is no problem.
class Student():
def __call__(self):
print("I am a student!")
s = Student()
s() #I am a student!
This is implemented in a class __call__
. Methods with underscores like this are called built-in methods in Python, and sometimes called magic methods. Overriding these magic methods generally changes the internal behavior of the object. The above example allows a class object to have the called behavior.
Going back to the concept of decorators, decorators are required to accept a callable object. It is also possible to use classes to implement it. You can make the constructor of a class __init__()
accept a function, then overload __call__()
and return a function, or you can achieve the effect of a decorator function.
class logging(object):
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("debug: " + self.func.__name__)
return self.func(*args, **kwargs)
@logging
def greeting(name):
print("hello, " + name)
if __name__ == '__main__':
greeting("qinxue")
class decorator with parameters
class logging(object):
def __init__(self, level="INFO"):
self.level = level
def __call__(self, func):
def wrapper(*args, **kwargs):
print(self.level + ": func: " + func.__name__)
func(*args, **kwargs)
return wrapper
@logging(level="INFO")
def greeting(name):
print("hello, " + name)
if __name__ == '__main__':
greeting("qinxue")
A property is a special property that, when accessed, executes a piece of functionality (function) and returns a value. After defining the function of a class as a feature, when the object uses obj.name again, it is impossible to notice that its name is calculated by executing a function. The use of this feature follows the principle of unified access.
import math
class Circle:
def __init__(self, radius): #圆的半径radius
self.radius = radius
@property
def area(self):
return math.pi * self.radius**2 #计算面积
@property
def perimeter(self):
return 2*math.pi*self.radius #计算周长
c = Circle(10)
print(c.radius)
print(c.area) #可以像访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值
print(c.perimeter) #同上
For classmethod: Whether this method is called from an instance or a class, it passes the class as the first parameter. Specifically, both classes and objects can call it.
For staticmethod (static method): there are often some functions related to the class, but static methods need to be used when the runtime does not require the participation of instances and classes . For example, changing environment variables or modifying properties of other classes can be used static method. This is actually very similar to static functions and static variables in C++. Likewise, both classes and objects can call it.
class Student(object):
def __init__(self, name):
self.name = name
def printName(self):
print(self.name)
@staticmethod
def smethod(*arg):
print("Statics: ", arg)
@classmethod
def cmethod(*arg):
print("Class: ", arg)
s = Student("qinxue")
s.printName()# qinxue
Student.printName()# 会报错,因为类不可以直接调用非静态函数
s.smethod()# Statics: ()
Student.smethod()# Statics: ()
s.cmethod()# Class: (<class '__main__.Student'>,)
Student.cmethod()# Class: (<class '__main__.Student'>,)
When there are many decorators to decorate a function, its calling process is as follows:
@a
@b
@c
def f():
equal to
f = a(b(c(f)))
An example is as follows:
from functools import wraps
def a(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("a: " + func.__name__ + "...")
return func(*args, **kwargs)
return wrapper
def b(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("b: " + func.__name__ + "...")
return func(*args, **kwargs)
return wrapper
def c(func):
@wraps(func)
def wrapper(*args, **kwargs):
print("c: " + func.__name__ + "...")
return func(*args, **kwargs)
return wrapper
@a
@b
@c
def f(name):
print("hello, " + name)
if __name__ == '__main__':
f("qinxue")
# 输出的结果为:
# a: f...
# b: f...
# c: f...
# hello, qinxue
The above is a brief summary of decorators in python.
The reference articles are as follows:
https://www.zhihu.com/question/26930016
https://www.cnblogs.com/cicaday/p/python-decorator.html
https://www.cnblogs.com/wangyongsong/p/ 6750454.html
https://www.pythoncentral.io/difference-between-staticmethod-and-classmethod-in-python/