我有一个装饰器函数,我想同时应用于普通函数和生成器。当应用于正常功能时,它可以正常工作。但是,当将其应用于生成器时,装饰器内部的迭代循环将执行到最后,但此后脚本将引发错误:
TypeError: 'NoneType' object is not iterable
并退出脚本。
def decor(func):
def wrapper(*args, **kwargs):
func_name = func.__name__
is_generator = "_generator" in func_name
if is_generator:
for item in func(*args, **kwargs):
print(item)
else:
res = func(*args, **kwargs)
print(res)
return wrapper
@decor
def f():
return "a"
@decor
def f_generator():
for i in range(2):
yield "b"
f()
""" Output: a """
for item in f_generator():
print ("Processing item ", item)
"""
Output:
b
b
Traceback (most recent call last):
File "test.py", line 27, in <module>
for item in f_generator():
TypeError: 'NoneType' object is not iterable
"""
此外,当将装饰器应用于生成器时,将不执行外部生成器调用的print ("Processing item ", item)
。
从生成器中删除装饰器后,就可以调用生成器,并且它可以正常运行。
如何解决此问题,以便可以将装饰器应用于生成器并使它正常工作?
尝试通过异常处理错误会带走错误,并且脚本已完全执行,但是print ("Processing item ", item)
仍未执行。
答案 0 :(得分:1)
添加@decorator
时,f_generator()
中的for item in f_generator():
实际上是decor(f_generator)
。由于decor()
不会产生或返回任何内容,因此它本身是不可迭代的,因此应在yield item
周围加上for item in func(*args, **kwargs):
答案 1 :(得分:1)
问题出在最后一个循环上。您正在遍历函数wrapper
,因为调用f_generator()
时得到的结果
包装器不是迭代器。
您可以简单地将last for循环替换为对函数的调用。 this is a nice tutorial i learned a lot from about decorators