有这段代码:
def f():
return 3
return (i for i in range(10))
x = f()
print(type(x)) # int
def g():
return 3
for i in range(10):
yield i
y = g()
print(type(y)) # generator
为什么f
会在返回生成器语句时返回int
?我猜yield
和生成器表达式都返回生成器(至少在语句return 3
被删除时)但是当有一次返回生成器表达式时有其他一些函数编译规则,第二次有返回时里面有yield
个关键字?
这是在Python 3.3中测试的
答案 0 :(得分:9)
当很快在函数体中使用yield
语句时,它就变成了一个生成器。调用生成器函数只返回该生成器对象。它不再是正常的功能;生成器对象已经接管了控制权。
来自yield
expression documentation:
在函数定义中使用
yield
表达式足以使该定义创建生成器函数而不是正常函数。当调用生成器函数时,它返回一个称为生成器的迭代器。然后该生成器控制生成器函数的执行。当调用其中一个生成器方法时,执行开始。
在常规函数中,调用该函数会立即将控制切换到该函数体,而您只是测试函数的结果,由它的return
语句设置。在生成器函数中,return
仍然表示生成器函数的结束,但这会导致引发StopIteration
异常。但是,在您调用4种生成器方法之一(.__next__()
,.send()
,.throw()
或.close()
)之前,生成器函数体根本不会执行。
对于您的特定功能f()
,您有一个常规功能,包含一个生成器。函数本身没什么特别的,除了它在return 3
被执行时提前退出。下一行上的生成器表达式独立存在,它不会影响定义它的函数。您可以在没有函数的情况下定义它:
>>> (i for i in range(10))
<generator object <genexpr> at 0x101472730>
使用生成器表达式生成一个生成器对象,就像在函数中使用yield
一样,然后调用该函数会生成一个生成器对象。所以你可以在g()
中调用f()
,其结果与使用生成器表达式相同:
def f():
return 3
return g()
g()
仍然是一个生成器函数,但在f()
中使用它会使不使f()
成为生成器函数。只有yield
可以做到这一点。
答案 1 :(得分:2)
def f():
return 3
return (i for i in range(10))
与
相同def f():
return 3
第二个return语句永远不会执行,只需在f
中生成一个表达式使其成为生成器。
答案 2 :(得分:1)
def f():
return 3
#unreachable code below
return (i for i in range(10))
我相信你的意思是:
def f():
yield 3
yield from (i for i in range(10))
答案 3 :(得分:0)
返回生成器不会使f
成为生成器函数。生成器只是一个对象,任何函数都可以返回生成器对象。如果您希望f
成为生成器函数,则必须在函数内使用yield
,就像使用g
一样。