python - python 函数返回生成器或普通对象的问题

标签 python iteration generator yield

我将函数 f 定义为

def f(flag):
    n = 10
    if flag:
        for i in range(n):
            yield i
    else:
        return range(n)

但是无论flag 是什么,f 都会返回一个生成器:

>>> f(True)
<generator object f at 0x0000000003C5EEA0>

>>> f(False)
<generator object f at 0x0000000007AC4828>

如果我遍历返回的对象:

# prints normally
for i in f(True):
    print(i)

# doesn't print
for i in f(False):
    print(i)

看起来 f(False) 返回一个已经迭代过的生成器。什么原因?谢谢。

最佳答案

包含 yield 语句的函数总是 返回生成器对象。

只有当你迭代那个生成器对象时,函数中的代码才会被执行。在此之前,函数中的任何代码都不会执行,Python 无法知道您将直接返回。

请注意,在生成器函数中使用 return 与在常规函数中使用不同的语义return 在这种情况下被简单地视为“在这里退出生成器”;返回值被丢弃,因为生成器只能通过 yield 表达式生成值。

看起来您想改用 yield from:

def f(flag):
    n = 10
    if flag:
        for i in range(n):
            yield i
    else:
        yield from range(n)

yield from 需要 Python 3.3 或更高版本。

参见 yield expression文档:

Using a yield expression in a function’s body causes that function to be a generator.

When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of a generator function. The execution starts when one of the generator’s methods is called. At that time, the execution proceeds to the first yield expression, where it is suspended again, returning the value of expression_list to the generator’s caller.

迭代生成器调用 generator.__next__() method , 触发执行。

如果您想有时返回生成器,则不要在此函数中使用yield。您可以通过其他方式生产发电机;例如,使用单独的函数,或者使用生成器表达式:

def f(flag):
    n = 10
    if flag:
        return (i for i in range(n))
    else:
        return range(n)

现在 f 中没有使用 yield,它不再直接生成生成器对象。相反,生成器表达式 (i for i in range(n)) 生成它,但只是有条件的。

关于python - python 函数返回生成器或普通对象的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25313283/

相关文章:

python - 对于 numpy 数组的每一行,将特定元素设置为 n

python - 更改由 nose 测试生成器创建的测试的名称

vb.net - 真随机数生成

python - pygame,如何获取图形的坐标?

python - 在 keras fit_generator 训练的第二个时期结束时无法将模型历史写入 json 文件

python - 越界分配给 python 数组——我是在重新发明一个轮子吗?

python - 通过迭代创建新的 df 列

time - N+N/2+N/4...迭代运行时间

python - 遍历堆栈(反向列表),是否有 isempty() 方法?

python - 快速打开和关闭csv?