理解装饰器的逻辑流程

时间:2018-03-15 17:19:28

标签: python decorator

我试图了解装饰器,所以我想从最简单的情况开始,检查/修改函数的输出:

示例1:

def checkIsFriend(func):
    def wrapper(arg):
        friends = ['alan', 'brian', 'carol']
        ret = arg # function not called
        if ret in friends:
            return 'hello {}, good to see you!'.format(ret)
        else:
            return 'Sorry {}, don\'t know you...'.format(ret)
    return wrapper

@checkIsFriend
def greet(name):
    return 'hi {}, good to see you!'.format(name)

print greet('alan')
print greet('simon')

# output:
# hello alan, good to see you!
# Sorry simon, don't know you...

示例2:

def reject_vowels(func):
    def wrapper():
        reject = 'aieou'
        new_str = []
        ret = func() # need to call the function
        for char in ret:
            if char in reject:
                continue
            new_str.append(char)
        return ''.join(new_str)
    return wrapper

@reject_vowels
def make_string():
    return 'hello world, how are you?'

print make_string()

# output:
# hll wrld, hw r y?

令我困惑的是,在示例1中,未调用装饰函数(arg)的参数。

在示例2中,我需要调用该函数。

有人可以解释这些例子的流程吗?

2 个答案:

答案 0 :(得分:1)

我的想法是wrapper替换装饰的函数; decorator语法是函数应用程序的缩写。

@checkIsFriend
def greet(name):
    ...

只是

的缩写
def greet(name):
    ...

greet = checkIsFriend(greet)

知道,checkIsFriend应定义为

def checkIsFriend(func):
    def wrapper(arg):
        friends = ['alan', 'brian', 'carol']
        if arg in friends:
            return func(arg)
        else:
            return 'Sorry {}, don\'t know you...'.format(arg)
    return wrapper

此处,func可能是您的greet函数或任何其他函数。在包装器中,我们对func一无所知,只是它需要一个参数并返回一个值。包装器是一个新函数,它使用与func相同的参数,实际上只是检查该参数的值来决定是简单地调用func还是返回不同的字符串。

如果我们为func定义帮助程序替换,可能会更有意义:

def checkIsFriend(func):
    friends = ['alan', 'brian', 'carol']

    def donotgreet(arg):
        return "Sorry {}, don't know you...".format(arg)

    def wrapper(arg):
        if arg in friends:
            f = func
        else:
            f = donotgreet
        return f(arg)

    return wrapper

所有包装器确定是否将其参数传递给并调用原始函数或装饰器定义的默认函数,具体取决于它接收的参数。

答案 1 :(得分:0)

你发布的装饰者会做不同的事情。

  • 在示例1中,修饰函数greet被一个新函数替换,其中一个参数arg不使用greet。事实上,如果您更改greet的正文以获取其他内容,则结果将完全相同。这个新函数用它接收的参数做一些操作并返回结果;它所做的操作类似于装饰函数greet,但它无论如何都与它无关,无论你正在装饰什么功能,它都是一样的。
  • 在示例2中,修饰函数make_string被一个没有调用make_string的参数的新函数替换,对其输出执行某些操作并返回结果。在这种情况下,如果您修饰了不同的函数,结果会有所不同,因为新函数实际上是使用装饰器接收的函数。

装饰器不要求你实际使用装饰函数(比如在函数中使用参数不需要你实际使用它)。他们只会用他们返回的值替换装饰的东西,它可以是任何。通常它是你可以调用并且与装饰函数做相关的东西,因为否则它通常不是很有用(例如,在例1中你可以只有一个常规函数wrapper做了什么,但没有必要。