Python: 练习 装饰器 带有参数的装饰器 类装饰器 多个装饰器装饰一个函数Python: 练习 装饰器 带有参数的装饰器 类装饰器 多个装饰器装饰一个函数Python: 练习 装饰器 带有参数的装饰器 类装饰器 多个装饰器装饰一个函数Python: 练习 装饰器 带有参数的装饰器 类装饰器 多个装饰器装饰一个函数
  • 首页
  • 博客
  • 书签
  • 文件
  • 分析
  • 登录

Python: 练习 装饰器 带有参数的装饰器 类装饰器 多个装饰器装饰一个函数

发表 admin at 2022年6月16日
类别
  • Practice
标签

练习

# 装饰器
def decorator_1(func):
    print(f"装饰1:{func}")

    def inner(*args, **kwargs):
        print(f"inner1:{func}")
        return func(*args, **kwargs)

    return inner

# 带有参数的装饰器
def decorator_2(arg):
    def decorator_2_(func):
        print(f"装饰2:{func}")

        def inner(*args, **kwargs):
            print(f"inner2:{func}")
            print(f"decorator_2 参数:{arg}")
            return func(*args, **kwargs)

        return inner

    return decorator_2_

# 类装饰器
class Decorator_cls(object):
    def __init__(self, func):
        self.func = func
        print(f"装饰cls:{self.func}")

    def __call__(self, *args, **kwargs):
        print(f"cls__call__:{self.func}")
        return self.func(*args, **kwargs)

# 多个装饰器装饰一个函数
@decorator_1  # sum_func = decorator_1(sum_func)
@decorator_2("abc")
@Decorator_cls
def sum_func(a, b=0):
    sum_ = a + b
    return sum_


result = sum_func(1, b=2)
print(f"结果:{result}")

运行结果:

装饰cls:
装饰2:<__main__.decorator_cls object at 0x00000000023FA700>
装饰1:.decorator_2_..inner at 0x00000000026A2160>
inner1:.decorator_2_..inner at 0x00000000026A2160>
inner2:<__main__.decorator_cls object at 0x00000000023FA700>
decorator_2 参数:abc
cls__call__:
结果:3

Python多个装饰器的执行顺序

当Python函数被多个装饰器装饰时,装饰顺序和执行顺序是怎样的,用一个简单的例子来说明

def decorator_a(func):
    print('Get in decorator_a')

    def inner_a(*args, **kwargs):
        print('Get in inner_a')
        return func(*args, **kwargs)
    return inner_a


def decorator_b(func):
    print('Get in decorator_b')

    def inner_b(*args, **kwargs):
        print('Get in inner_b')
        return func(*args, **kwargs)

    return inner_b


@decorator_b
@decorator_a
def f(x):
    print('Get in f')
    return x * 2


if __name__ == '__main__':
    a = f(2)
    print("a =",a)

执行文件得到的结果是:

Get in decorator_a
Get in decorator_b
Get in inner_b
Get in inner_a
Get in f
a = 4

我们来分析一下,为什么会是这样的顺序:

首先注释掉代码的执行部分,即a = f(2),执行文件,只打印两行:

Get in decorator_a
Get in decorator_b

这说明装饰器函数在被装饰函数定义好后就立即执行。

而且执行顺序是由下到上开始装饰。调用decorator_a时,f被装饰成inner_a,调用decorator_b时,f被装饰成inner_b。

通过在最后执行:print(f),可验证。

def decorator_a(func):
    ...
    return inner_a


def decorator_b(func):
    ...
    return inner_b


@decorator_b
@decorator_a
def f(x):
    print('Get in f')
    return x * 2


if __name__ == '__main__':
    print(f)

执行结果为:

Get in decorator_a
Get in decorator_b
.inner_b at 0x0000019C6FC62820>

所以当调用函数执行时,a=f(2),f已经变成了inner_b,而inner_b中return的func,实则为inner_a,inner_a中return的func才是最终的f。

所以最后的调用顺序为:

inner_b —>inner_a—>f

执行部分打印的结果就为:

Get in inner_b
Get in inner_a
Get in f
a = 4

总结:

多个装饰器装饰函数时,规律是从下到上包裹(装饰)函数,然后从上到下执行。

 

练习 类中使用装饰器

def decorator(arg):
    print(f"decorator 参数:{arg}")

    def inner1(func):
        print(f"decorator inner1 参数:{func}")

        def inner2(*args, **kwargs):
            print(f"decorator inner2 参数:args {args}, kwargs {kwargs}")
            return func(*args, **kwargs)

        return inner2

    return inner1


class Test(object):
    def __init__(self):
        self.func_a(2, 3)

    @decorator(1)
    def func_a(self, *args, **kwargs):
        print(f"func_a 参数: args {args}, kwargs {kwargs}")

    def func_b(self):
        self.func_a(2, 3)


if __name__ == '__main__':
    obj = Test()
    # obj.func_a(2, 3)
    # obj.func_b()

练习

# 类装饰器带参数
class Outer(object):
    def __init__(self, arg):
        self.arg = arg
        print(f"Outer arg:{self.arg}")

    class DecoratorCls(object):
        def __init__(self, func):
            self.func = func
            print(f"装饰cls:{self.func}")

        def __call__(self, *args, **kwargs):
            print(f"cls__call__:{self.func}")
            return self.func(*args, **kwargs)

    def __call__(self, func):
        print(f"outer__call__:{self.DecoratorCls}")
        return self.DecoratorCls(func)


@Outer('is outer arg')  # sum_func = Outer('is outer arg')(sum_func)
def sum_func(a, b=0):
    sum_ = a + b
    return sum_


result = sum_func(1, b=2)
print(f"结果:{result}")

运行结果:

Outer arg:is outer arg
outer__call__:<class '__main__.Outer.DecoratorCls'>
装饰cls:
cls__call__:
结果:3

发表回复 取消回复

要发表评论,您必须先登录。

类别

  • Cat
  • Python
  • Django
  • Database
  • Html/CSS
  • JavaScript
  • Vue
  • RegExp
  • Maths/AI
  • PHP/Wordpress
  • Practice
  • Linux
  • Windows
  • Android
  • NAS
  • Software
  • Hardware
  • Network
  • SEO
  • English
  • Games
  • Recipes
  • General
  • Memorandum
  • Essays
  • 未分类

归档

©2015-2023 艾丽卡 Blog support@alaica.com
      ajax-loader