Python - 生成器案例,没有任何回报

时间:2013-07-18 01:41:23

标签: python for-loop generator

我有一个像这样的发电机:

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并抛出异常。

如何返回空发生器呢?

5 个答案:

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

这与这个问题的答案非常接近,但更为明确。