第一个装饰器
在Python中的装饰器可以提供一些额外的功能。装饰器本质上是一个Python函数(其实就是闭包),它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。装饰器用于一下场景,如:插入日志、性能测试、事务处理、缓存、权限校验等。
def simple_decorator(func):
def wrapper():
print("函数调用前")
func()
print("函数调用后")
return wrapper
@simple_decorator
def say_hello():
print("Hello")
say_hello()
"""
运行结果:
函数调用前
Hello
函数调用后
"""
import time
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 的执行时间为: {end_time - start_time} 秒")
return result
return wrapper
@timer_decorator
def say_hello(name):
time.sleep(1)
print(f"Hello, {name}")
say_hello("Python")
"""
运行结果:
Hello, Python
函数 say_hello 的执行时间为: 1.0007023811340332 秒
"""
多个装饰器
有时候需要多个装饰器修饰一个函数。
import time
def simple_decorator(func):
def wrapper():
print("函数调用前")
func()
print("函数调用后")
return wrapper
def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"函数 {func.__name__} 的执行时间为: {end_time - start_time} 秒")
return result
return wrapper
@timer_decorator
@simple_decorator
def say_hello():
time.sleep(1)
print("Hello")
say_hello()
"""
运行结果:
函数调用前
Hello
函数调用后
函数 wrapper 的执行时间为: 1.008784532546997 秒
"""
当有多个装饰器时,离函数近的装饰器会优先被执行。这里的执行顺序是decorator2 > decorator1
@decorator1
@decorator2
def function():
pass
这种顺序可以通过将装饰器看作是函数调用来理解
function = decorator1(decorator2(function))
带参数的装饰器
def decorator_with_args(decorator_arg1, decorator_arg2):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"装饰器参数: {decorator_arg1}, {decorator_arg2}")
func(*args, **kwargs)
return wrapper
return decorator
@decorator_with_args("Hello", "World")
def greet(name):
print(f"Hello, {name}")
greet("Python")
"""
运行结果:
装饰器参数: Hello, World
Hello, Python
"""
wraps装饰器
functool.wraps是Python的内置装饰器,用于在定义装饰器时保留原始函数的元信息(如函数名、文档字符串等)。如果不适用functools.wraps,装饰后的函数将丢失这些元信息。
def my_decorator(func):
# @wraps(func)
def wrapper(*args, **kwargs):
"""wrapper函数"""
print("Before call")
result = func(*args, **kwargs)
print("After call")
return result
return wrapper
@my_decorator
def greet(name):
"""Greet函数"""
print(f"Hello, {name}")
greet("CursorBot")
print(greet.__name__)
print(greet.__doc__)
"""
输出结果:
Before call
Hello, CursorBot
After call
wrapper
wrapper函数
"""
将注释掉的@wraps(func)复原后
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""wrapper函数"""
print("Before call")
result = func(*args, **kwargs)
print("After call")
return result
return wrapper
@my_decorator
def greet(name):
"""Greet someone."""
print(f"Hello, {name}")
greet("CursorBot")
print(greet.__name__)
print(greet.__doc__)
"""
运行结果:
Before call
Hello, CursorBot
After call
greet
Greet函数
"""
内置装饰器
property装饰器、staticmethod装饰器、classmethod装饰器
property装饰器用于类中的函数,可以让我们像访问属性一样来获取一个函数的返回值。
staticmethod装饰器同样用于类中的方法,这表示这个方式是一个静态方法,意味着该方法可以直接被调用无需实例化,同时也意味着它没有self参数,也无法访问实例化后的对象。
classmethod是一个类方法,无需实例化,没有self参数。与staticmethod的区别在于它会接收一个指向类本身的cls参数。
class User:
def __init__(self,name,age):
self.name = name
self.age = age
@property
def tell_name(self):
return f"我叫{self.name}"
@staticmethod
def say_hello():
print("Hello!")
@classmethod
def say_Hi(cls):
print(f"我是{cls.__name__}")
print("Hi!")
if __name__ == '__main__':
u1 = User("竹筒饭","18")
print(u1.tell_name)
User.say_hello()
User.say_Hi()
"""
运行结果:
我叫竹筒饭
Hello!
我是User
Hi!
"""
类装饰器
类能实现装饰器功能,是由于当调用一个对象时,实际上调用的是它的__call__方法
class classDecorator():
def __init__(self,func):
self.func = func
def __call__(self, *args, **kwargs):
print("class Decorator")
return self.func(*args, ** kwargs)
@classDecorator # 相当于myfunc = classDecorator(myfunc)
def myfunc():
print("my func")
if __name__ == '__main__':
myfunc()
"""
运行结果:
class Decorator
my func
"""