TypeError:将装饰器应用于生成器时,“ NoneType”对象不可迭代

时间:2019-01-02 09:31:46

标签: python python-3.x generator decorator python-decorators

我有一个装饰器函数,我想同时应用于普通函数和生成器。当应用于正常功能时,它可以正常工作。但是,当将其应用于生成器时,装饰器内部的迭代循环将执行到最后,但此后脚本将引发错误:

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)仍未执行。

2 个答案:

答案 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