[英]How to implement a decorator function
我对装饰器和闭合器是全新的,我尝试通过一个简单的示例进行练习。 执行时会引发以下错误:
NameError: name 'congratulate' is not defined
我需要更改什么?
"""
A recursive function to check if a string is a palindrome.
"""
@congratulate
def palindrome(phrase):
characters = [char.lower() for char in phrase if char.isalpha()]
chars_len = len(characters)
out1 = characters[0]
out2 = characters[-1]
if chars_len <= 2:
return out1 == out2
else:
if out1 == out2:
return palindrome(characters[1:-1])
else:
return False
def congratulate(func):
if func:
print('Congratulations, it\'s a palindrome!')
if __name__ == '__main__':
print(palindrome('Rats live on no evil star'))
"""
A recursive function to check if a string is a palindrome.
"""
def congratulate(func):
def wrapper(*argv, **kargs):
result = func(*argv, **kargs)
if result:
print('Congratulations, it\'s a palindrome!')
return result
return wrapper
@congratulate
def palindrome(phrase):
characters = [char.lower() for char in phrase if char.isalpha()]
chars_len = len(characters)
out1 = characters[0]
out2 = characters[-1]
if chars_len <= 2:
return out1 == out2
else:
if out1 == out2:
return palindrome(characters[1:-1])
else:
return False
if __name__ == '__main__':
print(palindrome('Rats live on no evil star'))
了解装饰器的本质是
@f
def g(args)
=>
f(g)(args)
将congratulate()函数移至正在装饰的函数上方(回文)。
我知道我参加晚会很晚,但我想扩大规模。
如前所述,在这种情况下, NameError
是由您在实际创建名称之前使用名称引起的。 将congratulate()
移到顶部可解决此问题。
NameError
Appart中,您有两个与装饰器/功能功能有关的隐式逻辑错误 : 首要问题:
congratulate
您的if
子句始终求值为True
; 当字符串是回文符时,您并不会完全祝贺您。 这是由于以下事实造成的:函数对象始终求值为True
,因此条件形式为if func:
的条件将始终执行:
def f():
pass
if f:
print("I'm true!")
# Prints: I'm true!
值得庆幸的是,这是微不足道的,并且可以通过实际调用if func("test string"):
函数来轻松解决if func("test string"):
第二期:
congratulate()
。 装饰器是一个可调用函数, 它返回可调用函数(可调用函数是诸如函数,在__call__
重载的类之类的东西)。 您的“装饰器”在这里所做的只是简单地接受一个函数对象,评估该对象是否为True
,然后打印出祝贺。
最糟糕的部分? 它还隐式地将palindrome
名称重新绑定为None
。
同样,您可以在下一个代码段中看到这种间接效果(押韵为+1):
def decor(f):
if f: print("Decorating can be tricky")
@decor
def f():
print("Do I even Exist afterwards?")
# When executed, this prints:
Decorating can be tricky
很酷,我们的函数f
已经过修饰,但是,看看我们尝试调用函数f
会发生什么:
f()
TypeError Traceback (most recent call last)
<ipython-input-31-0ec059b9bfe1> in <module>()
----> 1 f()
TypeError: 'NoneType' object is not callable
是的,我们的函数对象f
现在已分配给了decor
函数的返回值None
。
发生这种情况是因为@syntax
, @syntax
直接等效于以下内容:
@decor
def f(): pass
# similar to
f = decor(f) # we re-assign the name f!
因此,我们必须确保装饰器的返回值是一个可以随后再次调用的对象ergo,这是一个可调用的对象。
所以你会怎么做? 您可能会考虑的一种选择就是简单地返回您传递的函数:
def congratulate(func):
if func("A test Phrase!"):
print('Congratulations, it\'s a palindrome!')
return func
这将确保装饰器在您的palindrome()
函数上运行之后,名称palindrome
仍将映射到可调用对象。
问题? 事实证明这是一次性的 。 当Python遇到您的装饰器和函数时,它将执行一次 congratulate
,因此仅执行一次 if
子句。
但是, if
每次调用函数,都需要它来运行它! 为了做到这一点,您能做什么? 返回执行装饰功能 (所谓的嵌套函数装饰器)的功能 。
这样,您将为名称palindrome
创建一个新函数,并且该函数包含您的原始函数,该函数确保每次调用palindrome()
时都会执行该函数。
def congratulate(func): # grabs your decorated function
# a new function that uses the original decorated function
def newFunc():
# Use the function
if func("Test string"):
print('Congratulations, it\'s a palindrome!')
# Return the function that uses the original function
return newFunc
newFunc
现在是一个函数,它发出对原始函数的调用。
装饰过程现在将palindrome
名称分配给newFunc
对象(注意我们如何通过return newFunc
返回它。
结果,每次执行palindrome()
形式的调用时,该调用都会转换为newFunc()
,后者又在其主体中调用func()
。 (如果你仍然和我在一起,我赞扬你)。
最后的问题是什么? 我们已经对func
的参数进行了硬编码。 newFunc()
,每次调用palindrome()
函数newFunc()
都会使用func("Test String")
的调用签名调用原始函数func
,这不是我们想要的,我们需要能够传递参数。
有什么解决方案? 幸运的是,这很简单:将参数传递给newFunc()
,然后将其传递给func()
:
def congratulate(func): # grabs your decorated function
# a new function that uses the original decorated function
# we pass the required argument <phrase>
def newFunc(phrase):
# Use the function
# we use the argument <phrase>
if func(phrase):
print('Congratulations, it\'s a palindrome!')
# Return the function that uses the original function
return newFunc
现在,每当您调用palindrome('Rats live on no evil star')
这都会转换为对newFunc('Rats live on no evil star')
调用,该调用将以func('Rats live on no evil star')
if
子句中func('Rats live on no evil star')
。
执行后,这将非常有效,并为您带来所需的结果:
palindrome('Rats live on no evil star')
Congratulations, it's a palindrome!
希望您喜欢阅读,我相信我已经完成了!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.