Python 装饰器的多种使用方式

68 阅读4分钟

装饰器

装饰器是一个以函数为参数的函数,是将传入的函数进行包装,为其添加更多的功能。

可以很方便的在需要执行的函数前或函数后添加很多功能,或者做异常处理,但是可读性却不是很好。

奇怪的函数装饰器

def outer(fun):
    print("=========================")
    print("this is outer before func1")
    fun()
    print("this is outer after func1")
    print("=========================")


@outer
def func1():
    print("this is func1")


func1
=========================
this is outer before func1
this is func1
this is outer after func1
=========================

普通的函数装饰器

def outer2(fun):
    a = 10
    def inner():
        print("=========================")
        print("this is outer before func2")
        nonlocal a
        a -= 1
        print(a)
        fun()
        print("this is outer after func2")
        print("=========================")
    return inner


@outer2
def func2():
    print("this is func2")


@outer2
def func3():
    print("this is func3")


func2()
func2()
func3()
func3()
=========================
this is outer before func2
9
this is func2
this is outer after func2
=========================
=========================
this is outer before func2
8
this is func2
this is outer after func2
=========================
=========================
this is outer before func2
9
this is func3
this is outer after func2
=========================
=========================
this is outer before func2
8
this is func3
this is outer after func2
=========================

类作为装饰器

class ExceptionHandler:
    def __init__(self, func):
        self.func = func

    def __call__(self, *args, **kwargs):
        try:
            print("=========================")
            print(f"this is before {self.func.__name__}")
            ret = self.func(*args, **kwargs)
            print(f"this is after {self.func.__name__}")
            print("=========================")
            return ret
        except Exception as e:
            print(e)


@ExceptionHandler
def func2(a):
    print("this is func2")
    print(1/a)
    return 9

# 等价于
# func2 = ExceptionHandler(func2)


if __name__ == '__main__':
    print(func2(1))
    print(func2(0))
=========================
this is before func2
this is func2
1.0
this is after func2
=========================
9
=========================
this is before func2
this is func2
division by zero
None

类加上参数作为装饰器

class ExceptionHandler:
    def __init__(self, pre):
        self.pre = pre

    def __call__(self, func):
        def inner(*args, **kwargs):
            try:
                print("=========================")
                print(f"this is before {func.__name__}")
                print(self.pre)
                ret = func(*args, **kwargs)
                print(self.pre)
                print(f"this is after {func.__name__}")
                print("=========================")
                return ret
            except Exception as e:
                print(e)
        return inner


@ExceptionHandler(pre="xxxx")
def func2(a):
    print("this is func2")
    print(1/a)
    return 9

# 等价于
# func2 = ExceptionHandler(pre="xxxx")(add)


if __name__ == '__main__':
    print(func2(1))
    print(func2(0))
=========================
this is before func2
xxxx
this is func2
1.0
xxxx
this is after func2
=========================
9
=========================
this is before func2
xxxx
this is func2
division by zero
None

在类上添加装饰器

def add_str(string):
    def __str__(self):
        return str(self.__dict__)
    string.__str__ = __str__
    return string

@add_str
class MyClass:
    def __init__(self, a):
        self.a = a

# 等价于
# MyClass = add_str(MyClass)


if __name__ == '__main__':
    o = MyClass(10)
    print(o)
{'a': 10}

在类成员函数上添加装饰器

def excep(func):
    def wrapper(*args, **kwargs):
        try:
            print("=========================")
            print(f"this is before {func.__name__}")
            print(func(*args, **kwargs))
            print(f"this is after {func.__name__}")
            print("=========================")
        except Exception as e:
            print(e)
    return wrapper


class MyClass:
    def __init__(self, a):
        self.a = a
    @excep
    def test1(self, a):
        print("test1")
        print(1/a)


if __name__ == '__main__':
    o = MyClass(10)
    print(o)
    o.test1(5)
    o.test1(0)
<__main__.MyClass object at 0x000002EC6A9A7BE0>
=========================
this is before test1
test1
0.2
None
this is after test1
=========================
=========================
this is before test1
test1
division by zero

在类上和类成员函数上添加装饰器

def add_str(string):
    def __str__(self):
        return str(self.__dict__)
    string.__str__ = __str__
    return string


def excep(func):
    def wrapper(*args, **kwargs):
        try:
            print("=========================")
            print(f"this is before {func.__name__}")
            print(func(*args, **kwargs))
            print(f"this is after {func.__name__}")
            print("=========================")
        except Exception as e:
            print(e)
    return wrapper


@add_str
class MyClass:
    def __init__(self, a):
        self.a = a
    @excep
    def test1(self, a):
        print("test1")
        print(1/a)
        return 10
# 等价于
# MyClass = add_str(MyClass)


if __name__ == '__main__':
    o = MyClass(10)
    print(o)
    o.test1(5)
    o.test1(0)
{'a': 10}
=========================
this is before test1
test1
0.2
10
this is after test1
=========================
=========================
this is before test1
test1
division by zero

在类成员函数上添加类中函数作为装饰器

class Decorators:
    def log_function(func):
        def wrapper(*args, **kwargs):
            print("=========================")
            print(f"this is before {func.__name__}")
            print(f"args: {args}")
            ret = func(*args, **kwargs)
            print(ret)
            print(f"this is after {func.__name__}")
            print("=========================")
            return ret
        return wrapper

    @log_function
    def add(self, a, b):
        return a + b

    log_function = staticmethod(log_function)


d = Decorators()
print(d.add(3, 4))
=========================
this is before add
args: (<__main__.Decorators object at 0x000002DF473F8F70>, 3, 4)
7
this is after add
=========================
7

使用装饰器应用于类的所有函数/所有方法

def handle_exceptions(func):
    def wrapper(*args, **kwargs):
        try:
            print("=========================")
            print(f"this is before {func.__name__}")
            ret = func(*args, **kwargs)
            print(ret)
            print(f"this is after {func.__name__}")
            print("=========================")
            return ret
        except Exception as e:
            # 在这里添加统一的异常处理逻辑
            print(f"Exception caught: {str(e)}")

    return wrapper

# 装饰器应用于类的所有方法
def apply_exception_handler(cls):
    for name, method in cls.__dict__.items():
        if callable(method):
            setattr(cls, name, handle_exceptions(method))
    return cls

# 示例:一个带有异常处理的类
@apply_exception_handler
class MyClass:
    def method1(self):
        print("Method 1")
        raise ValueError("Error in method 1")

    def method2(self):
        print("Method 2")
        # 无异常抛出的情况

# 创建类的实例
my_instance = MyClass()

# 调用类的方法
my_instance.method1()
my_instance.method2()
=========================
this is before method1
Method 1
Exception caught: Error in method 1
=========================
this is before method2
Method 2
None
this is after method2
=========================