Python - 学习理解带参数的装饰器

理解带参数的装饰器

参考文章 Python精进-装饰器与函数对象

加了装饰器这段代码从一个函数定义(不会执行任何东西,在内存单元中保存一段代码)变成了一条赋值语句(修改被装饰函数所在内存单元中的内容)exit

  1. 从运维角度看是装饰器补充了函数的功能, 从开发角度看是装饰器将函数作为参数
  2. 函数返回的函数无法被直接调用,除非将其返回值赋值个一个变量;列表就相当于这个函数,他的元素必须通过带参数执行这个函数获得。
  3. 该用函数还是装饰器,可以看是谁调用谁,从参数传递的方向也可以判断。

第一步: 定义装饰函数

def foo(a):
    def decorator(func):
        def wrap(*args):
            if not callable(a):
                print(a)
            return func(*args)
        return wrap
    if callable(a):
        return decorator(a)
    return decorator

# 装饰器带参数可以使得被装饰函数的改变有两种可能

第二步:使用装饰器装饰函数,调用新函数

第一种可能用法

@foo('hello')
def bar(c):
    print(c)
    return 0

装饰器的处理过程

装饰的作用是获得一个新函数

  • bar = foo('hello')(bar)
  • 先执行 foo('hello') 得到 decorator 函数
  • 然后让decorator 函数带着(bar) 一起飞
  • 就变成了 bar = decorator(bar)
  • decorator(bar) 执行得到一个函数 wrap(名字不重要,为了得到内存中的地址而已)
  • 这个新函数可以有多个参数(因为原函数带参数,装饰后也要带参数啊)
  • 额外多说一句,函数里定义的函数是可变的(内存块里存的代码是可变的)
  • wrap 怎么写呢?根据外面的decorator函数的参数变着来:
    重点来了,开始改写bar:
  • 因为a='hello' not callable 所以有一行 print('hello') 的代码
  • 代码很少,接下来就 return了,return 的是被装饰函数的执行结果。
  • 为理解为wrap函数定义为这个时候去被装饰函数定义的内存块执行,并将被装饰函数的返回值返回出去。不知道这样说是否准确???
  • 相当于bar函数的函数体(内存中的块内容)变成了:
def bar(c):
    print(a)
    # 执行被装饰函数体
    print(c)
    # 将被装饰函数的返回值作为新函数的返回值,还是0
    return 0

调用被装饰后的函数显然应该为:

>>> bar('wold')
hello
world
0

第二种用法

@foo
def bar(c):
    print(c)
    return 0

装饰的作用是获得一个新函数

  • foo 函数是带参数的,所以把 bar作为参数执行 foo 函数 得到:
  • bar = foo(bar)
  • 仔细看foo的函数,如果参数是 callable 则返回 decorator 函数并且带上这个 foo 的参数,所以:
  • foo(bar) 变成了 decorator(bar) bar = decorator(bar)
  • 先执行 foo('hello') 得到 decorator
  • 于是 bar = decorator(bar)
  • decorator(bar) 执行得到的是一个 wrap 函数,说白了它的名字不重要,重要的是它里面的内容:
  • 里面的内容就这样来写 因为 a 是callable的,所以就不执行 print(a) 了,仅仅执行 func(*args),也就是将新函数的参数,被装饰函数返回它的返回值
  • 装饰器啥也没干,直接把被装饰器的代码拿去充数了。
  • 相当于bar函数的函数体(内存中的块内容)变成了:
def bar(c):
    # 执行被装饰函数
    print(c)
    # 将被装饰函数的返回值作为新函数的返回值,还是0
    return 0

调用被装饰后的函数应该为:

>>> bar('wold')
world
0

思考

定义一个函数其实是分配一个内存空间来装代码。
decorator() 函数执行的过程就是干这个事情:
创建一个 wrap 函数,最好把函数对象的引用丢出去。
这个函数干什么嗯
它先把print('hello') 这段代码记录下来。
再看decorator 的参数 func 是哪个,去他的代码块执行它,然后把返回值返回。

[参考]
https://www.jianshu.com/p/016573e8f63e

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文为《爬着学Python》系列第四篇文章。从本篇开始,本专栏在顺序更新的基础上,会有不规则的更新。 在Pytho...
    SyPy阅读 2,521评论 4 11
  • 部分细节自己改了点,也加了点自己例子,基本上属于转载。转载出处:https://my.oschina.net/le...
    洛克黄瓜阅读 2,001评论 0 3
  • 前言 Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pa...
    linheimx阅读 637评论 0 4
  • 每个人都有的内裤主要功能是用来遮羞,但是到了冬天它没法为我们防风御寒,咋办?我们想到的一个办法就是把内裤改造一下,...
    chen_000阅读 1,373评论 0 3
  • Python里我们经常能见到@开头的句法,也就是人们常说的装饰器(decorator)。装饰器是Python非常重...
    A遇上方知友阅读 891评论 0 0