python-类作为装饰器的各种情况

1.装饰器没有参数:
这时foo不再是之前的函数名而是类ClassDeco的一个对象,并且foo.func=foo,对象名()会触发类ClassDeco的__call__方法:

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

    def __call__(self, *args, **kwargs):
        print(f'Running {self.func.__name__}')
        self.func()
        print(f'End {self.func.__name__}')

@ClassDeco  # 等价于 foo = ClassDeco(foo)
def foo():
    print('do something')

foo()

"""
Running foo
do something
End foo
"""

2.装饰器有参数,被装饰函数没有参数
类名作为装饰器名,并且括号内有参数。先执行@后面的代码,类名加()形成一个对象,然后对象()触发类中的__call__方法,并且__call__方法中的func参数就是被装饰的函数名:

class ClassDeco:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __call__(self, func, *args, **kwargs):
        print(f'Running {func.__name__}')
        print(f'Using x + y = {self.x + self.y}')
        return func

@ClassDeco(1, 2)  # 等价于 foo = ClassDeco(1, 2)(foo)
def foo():
    print('do something')
    
foo()

"""
Running foo
Using x + y = 3
do something
"""

3.类装饰器不带参数,被包装对象带参数
类装饰器不带参数,就会直接将被装饰的函数名当做参数传入装饰器类的()中,触发装饰器类的__init__方法。此时的函数名是装饰器类的一个对象,这时的函数如果加括号调用,就会触发装饰器类当中的__call__方法,并且将参数传入到__call__方法当中的形参:

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

    def __call__(self, *args, **kwargs):
        print(f'Running {self.func.__name__}')
        self.func(*args, **kwargs)
        print(f'End {self.func.__name__}')


@ClassDeco  # 等价于foo = ClassDeco(foo)
def foo(a, b):
    print('do something')
    print(f'return a + b = {a + b}')

foo(1,2)

"""
Running foo
do something
return a + b = 3
End foo
"""

4.类装饰器带参数且被装饰对象也带参数

from functools import wraps


class ClassDeco:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __call__(self, func, *args, **kwargs):
        print(f'Using x + y = {self.x + self.y}')

        @wraps(func)
        def wrapper(*args, **kwargs):
            print('func',func.__name__)
            func(*args, **kwargs)
            print(f'Ending {func.__name__}')

        return wrapper


@ClassDeco(1, 2)  # (1)
def foo(a, b):
    print('do something')
    print(f'return a + b = {a + b}')

foo(5,8)  # (2)
# 执行结果:
"""
Using x + y = 3
func foo
do something
return a + b = 13
Ending foo
"""

(1) 这行代码相当于:foo = ClassDeco(1,2)(foo),执行过程中ClassDeco(1,2)是先生成一个ClassDeco对象,此时会执行__init__方法。再执行对象(foo),会触发__call__方法,并且会将函数名foo当做参数传入到__call__中,所以会首先执行print(f'Using x + y = {self.x + self.y}'),并且self.x = 1,self.y = 2。此时定义了函数wrapper,并且把wrapper返回给foo,所以此时的foo就是wrapper,但是此时的wrapper并没有执行。
(2) 函数名加括号,此时的函数名是装饰器类ClassDeco中__call__的返回值wrapper,所以函数名加括号就相当于wrapper(5,8)。在wrapper中func(*args,**kwargs)才是真正执行foo(5,8)的代码

posted @ 2023-06-09 17:35  ERROR404Notfound  阅读(24)  评论(0编辑  收藏  举报
Title