python装饰器(Decorator)

python装饰器(Decorator) v1

    1. 简述装饰器
    1. 常见的装饰器
    1. 装饰器的应用
    1. 总结

1. 简述装饰器:

1.1 装饰器的功能

装饰器可以让其他函数或类在不需要做额外代码修改的前提下,在代码运行期间动态增加功能的方式。(运行时,动态的给函数或者类添加功能。)

1.2 装饰器的本质

装饰器本质上是一个接受函数作为参数的可调用对象(通常是函数),并返回一个新的函数对象。这个新的函数对象通常会包装或扩展原始函数的行为。(装饰器本质上是一个python函数或类。)

装饰器的返回值也是一个函数/类对象。

1.3 装饰器的应用

装饰器常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。

1.4 装饰器的语法

装饰器是语法糖:利用更简洁流畅的语法实现更为复杂的功能。

使用@ 函数名/类名 可以实现给绑定函数/类额外功能。

1.5 装饰器的引导

# 将函数存储在变量中
def print_message(message):
    print(f'send message:{message}')

# 变量名引用函数名
send_message = print_message 
send_message('Hi, python!') # send message:Hi, python!
print(type(send_message), type(print_message)) # <class 'function'> <class 'function'>
# 相同的地址
print(id(send_message), id(print_message)) # 2664582954528 2664582954528
# 将函数作为参数传递给另外一个函数
def return_message(message):
    return f'send message:{message}'

def call_message(func, message):
    print(func(message))

call_message(return_message, 'Hi, python!') # send message:Hi, python!
# 函数嵌套
def func(outer_message):
    def print_message(message):
        print(f'print message:{message}')
    return print_message(outer_message)

func('Hi, python!') # print message:Hi, python!
# 闭包
def outer():
  def inner(message):
      print(f'print message:{message}')
  return inner

send_message = outer()
send_message('Hi, python!') # print message:Hi, python!
# 装饰器
def my_decorator(func):
    def wrapper():
        print('my_decorator_wrapper')
        func()
    return wrapper

@ my_decorator # 或 @my_decorator
def print_message():
    print('Hi, python!')

print_message()
执行结果:
my_decorator_wrapper
Hi, python!


# 通过函数嵌套实现同样的功能
def my_decorator(func):
    def wrapper():
        print('my_decorator_wrapper')
        func()
    return wrapper

def print_message():
    print('Hi, python!')

func = my_decorator(print_message)
func()

2. 常见的装饰器

Python中常见的装饰器:函数装饰器、类装饰器、属性装饰器、方法装饰器。

2.1 函数装饰器是最常见的装饰器:

# 记录函数的执行时间
import time

def timer(func):
    def wrapper(*args, **kwargs):
        startTime = time.time()
        res = func()
        endTime = time.time()
        print(f'执行时间:{endTime - startTime:.2f}秒') # 计算函数的执行时间
        return res
    return wrapper

@ timer
def myFunction():
    time.sleep(1)
    print('函数执行完毕')

myFunction()
执行结果:
函数执行完毕
执行时间:1.00

2.2 类装饰器

# 为类添加一个name的属性
def addName(cls):
    cls.name = 'MyClass' # 为类添加属性并赋值
    return cls

@ addName
class MyClass:
    pass

print(MyClass.name)
执行结果:
MyClass

2.3 属性装饰器(装饰类的属性,在不改变原属性定义的情况下,为属性添加一些额外的功能):

# 添加类属性检查功能
def typeCheck(attrType):
    def decorrator(func):
        def wrapper(self, value):
            if not isinstance(value, attrType): # 检测类型(int)
                raise ValueError(f'属性必须是 {attrType} 类型')
            func(self, value)
        return wrapper
    return decorrator

class MyClass:
    @ typeCheck(int)
    def setValue(self, value):
        self._value = value

myObj = MyClass()
myObj.setValue(10)
myObj.setValue('python') # 抛出异常  # ValueError: 属性必须是 <class 'int'> 类型

2.4 方法装饰器(装饰类的方法):

# 为类方法添加缓存
def cache(func):
    cacheDict = {} # 缓存数据
    def wrapper(self, *args):
        key = (func.__name__, args)
        if key in cacheDict:
            print('从缓存中读取数据')
            return cacheDict[key]
        print('计算结果并缓存')
        res = func(self, *args)
        cacheDict[key] = res
        return res
    return wrapper

class MyClass:
    @cache
    def getValue(self, x):
        return x ** 2

myObj = MyClass()
print(myObj.getValue(2))
print(myObj.getValue(2))

执行结果:
计算结果并缓存
4
从缓存中读取数据
4

2.5 python常见的内部装饰器:

2.5.1静态方法装饰器@staticmethod

静态方法是一种特殊类型的方法,它不需要特殊的第一个参数(如实例方法需要self或类方法需要cls)。静态方法可以通过在方法定义前加上@staticmethod装饰器来创建。

class MyClass:  
    @staticmethod  
    def my_static_method(arg1, arg2):  
        """这是一个静态方法,它不接受特殊的第一个参数。"""  
        return arg1 + arg2  
  
    def my_instance_method(self, arg1):  
        """这是一个实例方法,它接受'self'作为第一个参数。"""  
        return self.my_static_method(arg1, 10)  
  
# 使用静态方法  
result = MyClass.my_static_method(5, 7)  
print(result)  # 输出:12  
  
# 创建类的实例并使用实例方法  
instance = MyClass()  
result_instance = instance.my_instance_method(3)  
print(result_instance)  # 输出:13

静态方法在功能上类似于模块级别的函数,但是它们被包含在类的命名空间中,这有助于组织代码并提供一种将相关函数分组的方式。静态方法通常用于执行与类无关的操作,这些操作不需要访问或修改类的状态。

值得注意的是,静态方法也可以被类的实例调用,但是它们不会接收到实例引用作为第一个参数,因此它们不能访问或修改实例的状态。如果需要在静态方法中访问类级别的状态,可以显式地传递类名或使用MyClass.前缀来引用类属性。

2.5.2 类方法装饰器@classmethod

类方法是一种特殊类型的方法,它使用@classmethod装饰器来定义,并且第一个参数总是类本身,通常用cls作为参数名。类方法可以在不创建类实例的情况下调用,并且可以访问和修改类级别的状态。

class MyClass:  
    class_variable = "I am a class variable"  
  
    @classmethod  
    def my_class_method(cls, arg1):  
        """这是一个类方法,它接受'cls'作为第一个参数,可以访问和修改类变量。"""  
        print(cls.class_variable)  
        cls.class_variable = "Class variable has been changed"  
        return arg1 * 2  
  
# 使用类方法  
result = MyClass.my_class_method(5)  
print(result)  # 输出:10  
  
# 检查类变量是否已被修改  
print(MyClass.class_variable)  # 输出:Class variable has been changed  
  
# 创建类的实例并调用类方法  
instance = MyClass()  
print(instance.class_variable) # 输出:Class variable has been changed
instance_result = instance.my_class_method(3)  
print(instance_result)  # 输出:6    
print(instance.class_variable)  # 输出:Class variable has been changed

MyClass.class_variable = 'I am a class variable'
print(MyClass.class_variable) # 输出:I am a class variable
print(instance.class_variable)  # 输出:I am a class variable

instance.class_variable = 'instance.class_variable'
print(MyClass.class_variable) # 输出:I am a class variable
print(instance.class_variable)  # 输出:instance.class_variable

类方法通常用于执行与类相关但不依赖于特定实例的操作,例如工厂方法模式、修改类级别的状态或访问类级别的配置。它们也可以在元类编程中非常有用,因为它们可以修改类的定义。

要注意的是,尽管类方法可以通过实例调用,但它们仍然接收类本身作为第一个参数,而不是实例。如果你需要在方法中访问实例状态,那么应该使用实例方法。

2.5.3 描述符装饰器@property

它用于将一个方法变成属性调用的形式。在类定义中,可以使用 @property 装饰器来定义 getter 方法,允许像访问数据属性一样访问方法。setter 方法装饰器@<property_name>.setter。deleter 方法装饰器@<property_name>.deleter。

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        """Getter for radius."""
        return self._radius

    @radius.setter
    def radius(self, value):
        """Setter for radius."""
        if value < 0:
            raise ValueError("Radius cannot be negative!")
        self._radius = value
        
    @radius.deleter
    def radius(self):
        del self._radius

    @property
    def diameter(self):
        """Compute the diameter based on the radius."""
        return 2 * self._radius

    # 使用 @property 装饰器  


circle = Circle(5)
print(circle.radius)  # 输出:5,调用了 getter 方法  

# 尝试设置 radius 属性  
circle.radius = 10  # 调用了 setter 方法  
print(circle.radius)  # 输出:10  

# 尝试获取 diameter 属性  
print(circle.diameter)  # 输出:20,调用了 diameter 的 getter 方法  

# 尝试删除 radius 属性(没有定义 deleter,将会引发 AttributeError)  
# del circle.radius  

radius 是一个带有 getter 和 setter 方法的属性。你可以像访问普通属性一样访问它,但实际上是在调用方法。diameter 是一个只有 getter 方法的属性,所以它是只读的。

使用 @property 装饰器的好处是,你可以在不改变代码调用方式的情况下,轻松地添加额外的逻辑到属性的访问和修改过程中。可以在 setter 方法中添加验证逻辑,或者在 getter 方法中添加缓存逻辑。

2.5.4 抽象方法装饰器(abc.abstractmethod)@abstractmethod

它用于指示一个方法是抽象的,即这个方法在抽象基类中不应该有具体的实现。子类在继承这个抽象基类时,必须提供这个抽象方法的具体实现。如果没有实现,子类也将被视为抽象类,不能被直接实例化。@abstractmethod 是 Python 的 abc(抽象基类)模块中的一个装饰器。

from abc import ABC, abstractmethod  
  
class Shape(ABC):  
  
    @abstractmethod  
    def area(self):  
        """计算形状的面积"""  
        pass  
  
    @abstractmethod  
    def perimeter(self):  
        """计算形状的周长"""  
        pass  
  
# 一个遵循 Shape 接口的具体类  
class Circle(Shape):  
    def __init__(self, radius):  
        self.radius = radius  
  
    def area(self):  
        return 3.14159 * (self.radius ** 2)  
  
    def perimeter(self):  
        return 2 * 3.14159 * self.radius  
  
# 另一个遵循 Shape 接口的具体类  
class Rectangle(Shape):  
    def __init__(self, width, height):  
        self.width = width  
        self.height = height  
  
    def area(self):  
        return self.width * self.height  
  
    def perimeter(self):  
        return 2 * (self.width + self.height)  
  
# 尝试实例化抽象基类 Shape 会引发 TypeError  
# shape = Shape()  
  
# 实例化具体类 Circle 和 Rectangle 是可以的  
circle = Circle(5)  
print(circle.area())  # 输出:78.53975  
print(circle.perimeter())  # 输出:31.4159  
  
rectangle = Rectangle(4, 6)  
print(rectangle.area())  # 输出:24  
print(rectangle.perimeter())  # 输出:20

Shape 是一个抽象基类,它定义了两个抽象方法 area 和 perimeter。Circle 和 Rectangle 是 Shape 的子类,它们分别实现了这两个方法。如果你尝试直接实例化 Shape 类,Python 会抛出一个 TypeError,因为 Shape 是一个抽象基类,不能被直接实例化。

使用 @abstractmethod 可以确保你的代码更加健壮,因为它强制要求子类提供必要的方法实现。

3. 装饰器的应用

装饰器的应用:函数装饰函数、函数装饰类、类装饰函数、类装饰类。

# 函数装饰函数
import functools
def outer(func):
    @functools.wraps(func) # 用于保存被装饰的类或函数名
    def wrapper(*args, **kwargs):
        print('wrapper')
        return func(*args, **kwargs)
    return wrapper
@outer
def func():
    pass
func() # wrapper
# 函数装饰类
def outer(cls):
    @functools.wraps(cls)
    def wrapper(*args, **kwargs):
        print('wrapper')
        return cls(*args, **kwargs)
    return wrapper
@outer
class Foo:
    pass
f = Foo() # wrapper
# 类装饰函数:定义一个类装饰器,装饰函数,默认调用__call__方法
class Wrap:
    def __init__(self, func):
        self._func = func
    def __call__(self, *args, **kwargs): # 类装饰器要实现__call__方法
        print('Wrap', self._func.__name__)
        return self._func(*args, **kwargs)
@Wrap
def func():
    pass
func() # Wrap func

# 通过类方法实现装饰器
class Wrap:
    def wrapFunc(self):
        print('wrapFunc')
        return self
@Wrap.wrapFunc
def func():
    pass
func() # wrapFunc


# 带计数的装饰器
class Count:
    def __init__(self, func):
        self.func = func
        self.num_calls = 0

    def __call__(self, *args, **kwargs):
        self.num_calls += 1
        print(f'num of calls is:{self.num_calls}')
        return self.func(*args, **kwargs)

@Count # 等价于example = Count(example)
def example():
    print('Hi, python!')

example()
执行结果:
num of calls is:1
Hi, python!

example()
执行结果:
num of calls is:2
Hi, python!
# 类装饰类
class Wrap:
    def __init__(self, cls):
        self._cls = cls
    def __call__(self, *args, **kwargs):
        print('Wrap')
        return self._cls(*args, **kwargs)
@Wrap
class C:
    pass
c = C()
# 装饰器通用示例
import functools
def my_decorator(func):
# 保留原函数的元信息(原函数的元信息拷贝到对应的装饰器函数里)
   @functools.wraps(func) 
   def wrapper(*args, **kwargs):
       print("Before calling the function")
       result = func(*args, **kwargs)
       print("After calling the function")
       return result
   return wrapper

# 在使用装饰器的时候名字才会被替换,add.__name__就会变成wrapper。使用functools.wraps(func)保存元信息。
@my_decorator
def add(x, y):
   return x + y

print(add.__name__) # add

'''
如果不使用@functools.wraps(func)
print(add.__name__) # wrapper
'''

带参数的装饰器:

# 带参数的函数装饰器(在增加一层嵌套)
def repeat(num): # 接收装饰器参数,@repeat(3)
    def my_decorator(func): # 接收装饰器函数/类名
        @functools.wraps(func)
# 接收要执行函数参数,print_message(*args, **kwargs)
        def wrapper(*args, **kwargs): 
            for i in range(num):
                func(*args, **kwargs)
        return wrapper
    return my_decorator

@repeat(3) # 传入循环执行的次数
def print_message():
    print('Hi, python!')

print_message()
print(print_message.__name__)
执行结果:
Hi, python!
Hi, python!
Hi, python!
print_message
# 带参数的类装饰器
class Count:
# 接收装饰器的参数,Count(*args,**kwargs)
    def __init__(self, *args, **kwargs): 
        self.args = args
        self.kwargs = kwargs
        self.num_calls = 0

    def __call__(self, func): # 接收函数或类名
        @functools.wraps(func)
# 接收要装饰的函数或类的参数,example(*args, **kwargs)
        def wrapper(*args, **kwargs): 
            print('self.args:', self.args)
            print('self.kwargs:', self.kwargs)
            self.num_calls += 1
            print(f'num of calls is:{self.num_calls}')
            return func(*args, **kwargs)
        return wrapper

@Count('aaa')
def example():
    print('Hi, python!')

example()
print(example.__name__)

执行结果:
self.args: ('aaa',)
self.kwargs: {}
num of calls is:1
Hi, python!
example
# 描述符装饰器
class MyClass:
    @property
    def value(self):
        print('MyClass().value')
    @value.setter
    def value(self, message):
        print(message)
obj = MyClass()
obj.value # MyClass().value
obj.value = 'Hi, python!' # Hi, python!
obj.value # MyClass().value

# 等价于:
class MyClass:
    def get_value(self):
        print('MyClass().value')
    def set_value(self, message):
        print(message)
    def del_value(self):
        pass
    value = property(get_value, set_value, del_value, 'value...')
obj = MyClass()
obj.value # MyClass().value
obj.value = 'Hi, python!' # Hi, python!
obj.value # MyClass().value
print('doc:', MyClass.value.__doc__) # doc: value...
# 自定义实现描述符装饰器(__get__()、__set__()、__delete__())
class MyProperty:
    def __init__(self, func):
        self.func = func
        self.name = func.__name__
        self.cache = {} # 缓存装饰器
    def __get__(self, instance, owner):
        if instance is None:
            return self
        if self.name not in self.cache:
            value = self.func(instance)
            print('value:', value)
            print('self.cache:', self.cache)
            self.cache[self.name] = value
            print('self.cache:', self.cache)
        return self.cache[self.name]
    def __set__(self, instance, value):
        print(value)
        self.cache[self.name] = value

class MyClass:
    @MyProperty
    def value(self):
        print('MyClass().v`alue')

print('--'*5)
obj = MyClass()
obj.value # MyClass().value
# 修改了value的指向,self.cache[self.name]
obj.value = 'Hi, python!' # Hi, python! 
print(obj.value) # Hi, python!
# print(obj.zz) # AttributeError: 'MyClass' object has no attribute 'zz'
执行结果:
----------
MyClass().value
value: None
self.cache: {}
self.cache: {'value': None}
Hi, python!
Hi, python!


print('--'*5)
obj1 = MyClass()
obj1.value # 从缓存取数据self.cache
print(obj1.value) # Hi, python!
obj1.value = 'obj1.value' # obj1.value
print(obj.value) # obj1.value (从缓存取数据,self.cache)
执行结果:
----------
Hi, python!
obj1.value
obj1.value
# 装饰类的装饰器 (输入是类,输出也是类)
import time

# timer_decorator装饰器接收一个类作为参数,并返回一个继承自原始类的新类TimerClass。TimerClass中重写了__getattribute__方法,在调用类的方法时,会计算方法的执行时间并进行打印。
def timer_decorator(cls):
    class TimerClass(cls):
        def __getattribute__(self, item):
            attribute = object.__getattribute__(self, item)

            if callable(attribute):
                def wrapped_method(*args, **kwargs):
                    start_time = time.time()
                    result = attribute(*args, **kwargs)
                    end_time = time.time()
                    execution_time = end_time - start_time
                    print(f'Method {item} exectued in {execution_time} sec-onds.')
                    return result
                return wrapped_method
            else:
                return attribute

    return TimerClass

@timer_decorator
class MyClass:
    def my_method(self):
        time.sleep(2)
        print('Executing my_method')

@timer_decorator
class MyClass1:
    def my_method(self):
        time.sleep(2)
        print('Executing my_method')
    def print_message(self):
        print('message')


obj = MyClass()
obj.my_method()

obj = MyClass1()
obj.my_method()
obj.print_message()

输出结果:
Executing my_method
Method my_method exectued in 2.0033464431762695 seconds.
Executing my_method
Method my_method exectued in 2.0055508613586426 seconds.
message
Method print_message exectued in 0.0 seconds.
# functools.partial
import time
import functools


class DelayFunc:
    def __init__(self,  duration, func):
        self.duration = duration
        self.func = func

    def __call__(self, *args, **kwargs):
        print(f'Wait for {self.duration} seconds...')
        time.sleep(self.duration)
        return self.func(*args, **kwargs)

    def eager_call(self, *args, **kwargs):
        print('Call without delay')
        return self.func(*args, **kwargs)


def delay(duration):
    """装饰器:推迟某个函数的执行。同时提供 .eager_call 方法立即执行
    """
    # 此处为了避免定义额外函数,直接使用 functools.partial 帮助构造
    # DelayFunc 实例
    return functools.partial(DelayFunc, duration)


@delay(duration=2)
def add(a, b):
    return a + b


# 这次调用将会延迟 2 秒
res = add(1, 2)
print(res)
# 这次调用将会立即执行
res = add.eager_call(1, 2)
print(res)
执行结果:
Wait for 2 seconds...
3
Call without delay
3
# 返回值指向其他函数的装饰器
def func1():
    print('func1')

def func2(func):
    return func1

@func2
def func3():
    print('func3')

func3() # func1
# 不会执行func3里面的print()
# 装饰器的嵌套
import functools

def my_decorator1(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('execute decorator1')
        result = func(*args, **kwargs)
        print('end execute decorator1')
        return result
    return wrapper

def my_decorator2(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('execute decorator2')
        result = func(*args, **kwargs)
        print('end execute decorator2')
        return result
    return wrapper

@my_decorator1
@my_decorator2
def print_message(message):
    print(message)

print_message('Hi, Python!')

执行结果:
execute decorator1
execute decorator2
Hi, Python!
end execute decorator2
end execute decorator1

装饰器执行的嵌套顺序:从内到外定义,从外到内执行。

# 嵌套装饰器的执行顺序
def outer_decorator(func):
    def wrapper():
        print('执行顺序1')
        func()
        print('执行顺序4')
        return 2
    return wrapper

def inner_decorator(func):
    def wrapper():
        print('执行顺序2')
        func()
        print('执行顺序3')
        return 1
    return wrapper

@outer_decorator
@inner_decorator
def my_function():
    print("Function is being called")

my_function()
执行结果:
执行顺序1
执行顺序2
Function is being called
执行顺序3
执行顺序4

函数引用装饰器内的属性:

class fun:
    funA = 10
    funB = 20
    def __init__(self, func):
        self.func = func
        self.funa = 'funaaaaa'

    def __call__(self, *args, **kwargs):
        self.funb = 'funbbbbb'
        print('fun__call__')
        result = self.func(*args, **kwargs)
        return result

@fun
def f():
	"""函数引用装饰器内的属性"""
    print(f.funa)
    print(f.funb)
    print("f")
print('---f')
f()
执行结果:
---f
fun__call__
funaaaaa
funbbbbb
f
  • 简单的电商案例
# 电商领域有个功能明显可以使用“策略”模式,即根据客户的属性或订单中的商品计算折扣。
# 有1000或以上积分的顾客,每个订单享5% 折扣。
# 同一订单中,单个商品的数量达到20个或以上,享10%折扣。
# 订单中的不同商品达到10个或以上,享7%折扣。
# 假定一个订单一次只能享用一个折扣。
from collections import namedtuple

promos = []

def promotion(promo_func):
    promos.append(promo_func)
    return promo_func

@promotion
def fidelity(order):
    """为积分为1000或以上的顾客提供5%折扣"""
    return order.total() * .5 if order.customer.fidelity >= 1000 else 0

@promotion
def bulk_item(order):
    """单个商品为20个或以上时提供10%折扣"""
    discount = 0
    for item in order.cart:
        if item.quantity >= 20:
            discount += item.total() * .1
    return discount

@promotion
def large_order(order):
    """订单中的不同商品达到10个或以上时提供7%折扣"""
    distinct_items = {item.product for item in order.cart}
    if len(distinct_items) >= 10:
        return order.total() * .07
    return 0

def best_promo(order):
    """选择可用的最佳折扣"""
    return max(promo(order) for promo in promos)

Customer = namedtuple('Customer', 'name fidelity')

class LineItem:
    def __init__(self, product, quantity, price):
        self.product = product
        self.quantity = quantity
        self.price = price

    def total(self):
        return self.price * self.quantity

class Order:
    def __init__(self, customer, cart, promotions=None):
        self.__total = None
        self.customer = customer
        self.cart = list(cart)
        self.promotion = promotions

    def total(self):
        if not hasattr(self, '__total'):
# LineItem.total()
            self.__total = sum(item.total() for item in self.cart) 
        return self.__total

joe = Customer('John Doe', 1000) # 积分为1000
joe_cart = [LineItem('banana', 4, 5.0), LineItem('apple', 10, 1.5), LineI-tem('watermellon', 5, 5.0)]
joe_order = Order(joe, joe_cart)
print(best_promo(joe_order)) # 30.0    (20+15+25)*0.5

4. 总结

装饰器(Decorator)是 Python 中的一个高级功能,允许你修改或增强函数、方法或类的行为,而不需要修改它们的源代码。装饰器本质上是一个接受函数作为参数的可调用对象(通常是一个函数),并返回一个新的函数对象。这个新的函数对象通常会包装(wrap)或修改原始函数的行为。

  • 语法:

    • 使用 @decorator_name 语法将装饰器应用于函数、方法或类。

    • 装饰器可以应用于定义之前或之后的函数,但通常放在函数定义之前。

  • 工作原理

    • 当 Python 解释器遇到被装饰的函数时,它会立即执行装饰器函数,并将被装饰的函数作为参数传递给装饰器函数。
    • 装饰器函数返回一个“包装器”(wrapper)函数,这个包装器函数通常在被装饰的函数之前和/或之后执行某些操作,然后调用原始函数。
    • 原始函数的名称和文档字符串(如果有的话)通常会被复制到包装器函数中,以保持函数的身份不变。
  • 用途

    • 日志记录:在函数调用前后记录日志信息。
    • 性能测试:测量函数执行的时间。
    • 缓存:缓存函数的结果,避免重复计算。
    • 权限校验:在访问特定函数之前检查用户权限。
    • 事务管理:确保一系列操作要么全部成功,要么全部失败。
    • 函数参数校验:在函数调用前验证参数。
  • 嵌套装饰器:

    • 可以将多个装饰器应用于同一个函数。这通常是通过将多个装饰器函数依次应用于函数来实现的。
    • 嵌套装饰器的执行顺序是从内到外(即靠近函数定义的装饰器先执行),但装饰器函数本身的调用顺序是从外到内。
  • 类装饰器:

    • 除了函数可以作为装饰器之外,类也可以作为装饰器。
    • 当类被用作装饰器时,Python 会调用类的 call 方法来执行装饰操作。
  • 注意事项:

    • 装饰器可能会增加代码的复杂性,因此应该谨慎使用。
    • 如果装饰器改变了函数的行为,这可能会使代码更难理解和维护。
    • 使用装饰器时要确保它们不会引入意外的副作用或性能问题。
  • 使用场景:

    • 当你想要在不修改原始函数源代码的情况下增强函数功能时,装饰器是一个很好的选择。
    • 在设计框架或库时,装饰器可以作为一种灵活的方式来扩展功能或修改行为。
  • 示例:

    def my_decorator(func):  
        def wrapper():  
            print("Something is happening before the function is called.")  
            func()  
            print("Something is happening after the function is called.")  
        return wrapper  
      
    @my_decorator  
    def say_hello():  
        print("Hello!")  
      
    say_hello()
    执行结果:
    Something is happening before the function is called.
    Hello!
    Something is happening after the function is called.
    

一切callable的对象都可以被用来实现装饰器。

装饰器执行的嵌套顺序:从内到外定义,从外到内执行。

使用装饰器感到迷茫的时候,可以将装饰器用等价的形式转换。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

棠越

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值