前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python每日一题:装饰器(一)

Python每日一题:装饰器(一)

作者头像
用户7685359
发布2020-08-24 16:11:50
4990
发布2020-08-24 16:11:50
举报
文章被收录于专栏:FluentStudyFluentStudy

有什么问题或资源分享欢迎大家后台留言或添加微信

关于Python装饰器,考点很多,这里在网上找到一个对Python装饰器解释的很详细的回答。因为是英语的,并且比较长,将通过两篇来进行翻译。原文链接如下:

https://stackoverflow.com/questions/739654/how-to-make-a-chain-of-function-decorators/1594484#1594484

装饰器基础

一、函数是对象

要理解装饰器,你首先必须要知道在Python中,函数是对象。这一点对装饰器有着很重要的影响。让我们用一个简单的例子来看一下为什么:

代码语言:javascript
复制
def shout(word="yes"):
    return word.capitalize()+"!"

print(shout())
# 输出 : 'Yes!'

# 因为函数是一个对象,所以你可以像其他任何对象一样,将它赋值给另一个变量
scream = shout

# 注意,在赋值时,我们并没有使用括号(),即表示我们并没有在调用函数
# 我们只是将 "shout" 赋值给了变量 "scream"
# 通过赋值的操作意味着你可以通过调用 scream() 来达到调用 shout()的目的

print(scream())
# 输出 : 'Yes!'

# 更重要的是,你可以移除旧的函数名 "shout"
# 而这个函数仍然可以通过 screac() 来进行调用

del shout
try:
    print(shout())
except NameError, e:
    print(e)
    #输出: "name 'shout' is not defined"

print(scream())
# 输出: 'Yes!'

牢记这一点,我们过会将会回到这一点上。 对Python中的函数而言,另外一个有趣的特点就是在函数体内也可以定义函数。

代码语言:javascript
复制
def talk():

    # 你可以在 talk() 中定义一个函数
    def whisper(word="yes"):
        return word.lower()+"..."

    # 并且很快的调用它
    print(whisper())

# 你可以调用 "talk",每调用 "talk" 都会定义一次 "whisper"
# 而 "whisper" 在 "talk" 的函数体中被调用
talk()
# 输出: 
# "yes..."

# 但是 "whisper" 在 "talk" 外是不存在的
try:
    print(whisper())
except NameError, e:
    print(e)
    #输出 : "name 'whisper' is not defined"*
    #Python's functions are objects
二、函数引用

好了,你还在坚持看吗?现在到了有趣的部分了… 从上面,你已经知道了,Python中的函数是对象,因此,函数有如下两个特点:

  1. 可以赋值给另一个变量
  2. 可以定义在另一个函数中

这意味着一个函数可以作为另一个函数的返回值。

代码语言:javascript
复制
def getTalk(kind="shout"):

    # 在内部动态定义两个函数
    # 这里需要注意的是 on the fly 的翻译,我查了下,在计算机中,可理解为动态生成的。
    def shout(word="yes"):
        return word.capitalize()+"!"

    def whisper(word="yes") :
        return word.lower()+"...";

    # 然后返回其中一个
    if kind == "shout":
        # 没有使用 "()",即表示并没有调用函数
        # 返回函数对象
        return shout  
    else:
        return whisper

# 我们如何使用这个奇怪的特点

# 调用函数并且把它赋值给一个变量
talk = getTalk()      

# You can see that "talk" is here a function object:
# 你可以看到,这里的 "talk" 已经是一个函数对象
print(talk)
#输出 : <function shout at 0xb7ea817c>

# The object is the one returned by the function:
# 这个对象是 getTalk() 函数返回的一人对象
print(talk())
#输出 : Yes!

# 简单点,你也可以直接调用进行打印输出
print(getTalk("whisper")())
#输出 : yes...

还有更多别的用法! 如果你可以将函数作为返回值返回,那么函数同样也可以另外一个函数的参数

代码语言:javascript
复制
def doSomethingBefore(func): 
    print("I do something before then I call the function you gave me")
    print(func())

doSomethingBefore(scream)
#outputs: 
#I do something before then I call the function you gave me
#Yes!

好了,你现在做好了理解装饰器的准备知识。可以看到装饰器就是 "wrappers",装饰器可以让你在原来函数的代码之前和之前执行代码,并且不会修改原来函数本身。

三、手动实现装饰器

你会如何手动实现装饰器呢:

代码语言:javascript
复制
# 一个装饰器就是一个函数,它要求另一个函数作为参数
def my_shiny_new_decorator(a_function_to_decorate):

    # 在内部,装饰器定义了一个动态的函数:即包装器。
    # 这个函数是为了包装原来的函数
    # 所以它可以在原来函数之前和之后执行
    def the_wrapper_around_the_original_function():

        # 在这写代码,用来在被包装函数之前执行
        print("Before the function runs")

        # 调用被包装函数(用()来调用)
        a_function_to_decorate()

        # 在这写代码,用来在被包装函数之后
        print("After the function runs")

    # 在这一步,"a_function_to_decorate" 还没有被执行
    # 我们返回了刚创建的包装器函数
    # 这个包装器包括了被包装函数以及在它之前和之前要执行的代码。现在它已经准备好被使用了!
    return the_wrapper_around_the_original_function

# 现在想象你要创建一个函数,并且你以后永远也不会再调用它了
def a_stand_alone_function():
    print("I am a stand alone function, don't you dare modify me")

a_stand_alone_function() 
#输出: I am a stand alone function, don't you dare modify me

# 好了,你现在可以通过装饰它来扩展它的功能
# 只要将这个函数作为参数传递装饰器,它就会被自动包装上任何你想要的代码
# 并且通过返回一个新的函数让你使用

a_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function_decorated()
#输出:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

现在,你可能希望每次调用a_stand_alone_function时,都会调用a_stand_alone_function_修饰。这很简单,只需用my_shiny_new_decorator返回的函数覆盖a_stand_alone_function:(即你仍然希望使用原来的被包装的函数名来达到调用包装后的函数的目的,可以通过赋值实现)

代码语言:javascript
复制
a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)
a_stand_alone_function()
#outputs:
#Before the function runs
#I am a stand alone function, don't you dare modify me
#After the function runs

# 这就是装饰器真正做的!

个人英文水平有限,有什么不对的还请指教。

愿关注我们的人都能找到

属于自己的皮球

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-05-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FluentStudy 微信公众号,前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 装饰器基础
    • 一、函数是对象
      • 二、函数引用
        • 三、手动实现装饰器
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档