前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python装饰器和语法糖

python装饰器和语法糖

作者头像
烤粽子
发布2021-07-07 18:20:08
7600
发布2021-07-07 18:20:08
举报
文章被收录于专栏:粽子的深度学习笔记

装饰器在大工程中比较常见,那么如何理解装饰器呢?打个比方,假如你建好了一栋大房子,建好后还想加一些功能,这个时候房子的主体结构是不能动了,只好在现有房子的基础上做一些装饰/装修。这些装饰在不影响/不修改原来房子功能的基础上,增加了美观等功能。

装饰器是可调用的对象,其参数是另一个函数(被装饰的函数)。 装 饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个 函数或可调用对象。[2]

代码语言:javascript
复制
@decorate
def target():
    print('running target()')

def target():
    print('running target()')
target = decorate(target)

上述两种写法的代码效果一样。 上面出现的@符号就是装饰器的语法糖,它放在函数开始定义的地方,这样就可以省略最后一步再次赋值的操作。 注意:Python 中的函数和 Java、C++不太一样,Python 中的函数可以像普通变量一样当做参数传递给另外一个函数,例子如下:

代码语言:javascript
复制
def foo():
    print("foo")

def bar(func):
    func()

foo()
bar(foo)
bar

函数调用:

  • 不带括号时,调用的是这个函数本身 ,是整个函数体,是一个函数对象,不须等该函数执行完成
  • 带括号(参数或者无参),调用的是函数的执行结果,须等该函数执行完成的结果
代码语言:javascript
复制
# 装饰器通常把函数替换成另一个函数
def deco(func):
    def inner():
        print('running inner()')
    return inner # deco 返回 inner 函数对象

@deco
def target(): # 使用 deco 装饰 target。
    print('running target()')

# target = deco(target) # 有了语法糖这句可以省略  相当于 target = wrapper
target() # 调用被装饰的 target 其实会运行 inner。
代码语言:javascript
复制
running target()
代码语言:javascript
复制
target # 审查对象,发现 target 现在是 inner 的引用。
代码语言:javascript
复制
.inner()>
代码语言:javascript
复制
# 装饰器通常把函数替换成另一个函数
def deco(func):
    def inner():
        print('running inner()')
        return func()
    return inner # deco 返回 inner 函数对象

@deco
def target(): # 使用 deco 装饰 target。
    print('running target()')

# target = deco(target) # 有了语法糖这句可以省略  相当于 target = wrapper
target() # 调用被装饰的 target 其实会运行 inner。
代码语言:javascript
复制
running inner()
代码语言:javascript
复制
registry = [] # registry 保存被 @register 装饰的函数引用。

def register(func):  # register 的参数是一个函数。
    print('running register(%s)' % func) # 为了演示,显示被装饰的函数。
    # func.__name__ 显示被装饰函数的名字
    registry.append(func)  # 把 func 存入 registry。
    return func # 返回 func:必须返回函数;这里返回的函数与通过参数传入的一样。

@register 
def f1():
    print('running f1()')
    
@register
def f2():
    print('running f2()')

def f3(): 
    print('running f3()')
    
def main(): # main 显示 registry,然后调用 f1()、f2() 和 f3()。
    print('running main()')
    print('registry ->', registry)
    f1()
    f2()
    f3()
    
if __name__=='__main__':
    main() 
代码语言:javascript
复制
running register()
running register()
running main()
registry -> [, ]
running f1()
running f2()
running f3()

注意,register 在模块中其他函数之前运行(两次)。调用register 时,传给它的参数是被装饰的函数,例如 。

上面例子主要想强调,函数装饰器在导入模块时立即执行,而被装饰的函数只在明确调用时运行。这突出了 Python 程序员所说的导入时和运行时之间的区别。

考虑到装饰器在真实代码中的常用方式,上面例子有两个不寻常的地方。

  • 装饰器函数与被装饰的函数在同一个模块中定义。实际情况是,装饰器通常在一个模块中定义,然后应用到其他模块中的函数上。
  • register 装饰器返回的函数与通过参数传入的相同。实际上,大多数装饰器会在内部定义一个函数,然后将其返回。

[1] 廖雪峰 装饰器 [2] 流畅的python

我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=29v0kx6sv4w0s

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/06/22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档