我有一个像这样的发电机:
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并抛出异常。
如何返回空发生器呢?
答案 0 :(得分:8)
只需做一个简单的检查:
def iterate_my_objects_if_something(self):
if self.my_objects:
for x in self.my_objects:
if x.something:
yield x
答案 1 :(得分:3)
迭代前检查:
if self.my_objects:
for x in self.my_objects:
if x.something:
yield x
答案 2 :(得分:3)
重要的是要知道,哪个迭代会导致错误。这肯定是在追溯中指出的,但在这种情况下,追溯是没有必要的(继续阅读)。
看了之后,很明显,但值得澄清的是:
空生成器不属于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
答案 3 :(得分:0)
如果没有什么要迭代的,则抛出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)
答案 4 :(得分:0)
此答案在另一个问题中得到了回答:What is the difference between raise StopIteration and a return statement in generators?。
基本上,您只需要返回None即可结束生成器。提高StopIteration is now deprecated。
因此您的代码可以简单地是:
def iterate_my_objects_if_something(self):
if self.my_objects == []:
return
for x in self.my_objects:
if x.something:
yield x
这与这个问题的答案非常接近,但更为明确。