我有一个像这样的发电机:
def iterate_my_objects_if_something(self):
    for x in self.my_objects:
        if x.something:
            yield x
我这样称呼:
for x in self.iterate_my_objects_if_something():
    pass
在没有返回的情况下,这会尝试遍历 NoneType 并抛出异常。
我如何返回一个空的生成器?
只需做一个简单的检查:
def iterate_my_objects_if_something(self):
    if self.my_objects:
        for x in self.my_objects:
            if x.something:
                yield x
    重要的是要知道哪个迭代会导致错误。这肯定在回溯中指出,但在这种情况下,回溯不是必需的(继续阅读)。
看完之后,很明显,但值得澄清的是:
空生成器不是NoneType,因此迭代它不会导致这样的问题:
>>> def test_generator():
    for i in []:
        yield i
>>> list(test_generator())  # proof it is empty
[]
>>> for x in test_generator():
    pass
>>> 
生成器在定义期间被 Python 识别(我正在简化)并且尝试混合生成器和简单函数(例如,通过使用条件,如下所示)将是语法错误:
>>> def test_generator_2(sth):
    if sth:
        for i in []:
            yield i
    else:
        return []
SyntaxError: 'return' with argument inside generator (<pyshell#73>, line 6)
基于上面的结论是错误不是通过迭代器迭代,而是在创建它时会发生什么(生成器中的代码):
def iterate_my_objects_if_something(self):
    for x in self.my_objects:  # <-- only iteration inside generator
        if x.something:
            yield x
所以看起来在某些情况下self.my_objects变成了None.
要解决该问题:
self.my_objects始终是可迭代的(例如空列表[]),或在迭代之前检查它:
def iterate_my_objects_if_something(self):
    # checks, if value is None, otherwise assumes iterable:
    if self.my_objects is not None:
        for x in self.my_objects:
            if x.something:
                yield x
迭代前检查:
if self.my_objects:
    for x in self.my_objects:
        if x.something:
          yield x
    如果没有什么可以迭代抛出StopIteration异常。请参阅下面的示例。
def iterate_my_objects_if_something(self):
    if not self.my_objects:
        raise StopIteration
    for x in self.my_objects:
        if x.something:
            yield x
我会更进一步:
def iterate_my_objects_if_something(self):
    if not self.my_objects:
        raise StopIteration
    yield from (x for x in self.my_objects if x.something)
    这个答案在另一个问题中得到了回答:raise StopIteration 和生成器中的 return 语句有什么区别?.
基本上,您只需要返回 None 即可结束您的生成器。提高StopIteration 现在已弃用。
所以你的代码可以简单地是:
def iterate_my_objects_if_something(self):
    if self.my_objects == []:
        return
    for x in self.my_objects:
        if x.something:
            yield x
这非常接近这个问题的答案,但更明确。