在同一函数中使用return和yield
在Python中,当在同一个函数里同时使用yield和return时,会发生什么呢?
def find_all(a_str, sub):
start = 0
while True:
start = a_str.find(sub, start)
if start == -1: return
yield start
start += len(sub) # use start += 1 to find overlapping matches
这样的话,这个函数还是生成器吗?
4 个回答
1
注意:在下面的例子中,你不会看到StopIteration
这个错误。
def odd(max):
n = 0
while n < max:
yield n
n = n + 1
return 'done'
for x in odd(3):
print(x)
因为
for
循环会自动处理这个错误。这是它停止的信号。
不过,你可以用下面的方式来捕捉这个错误:
g = odd(3)
while True:
try:
x = next(g)
print(x)
except StopIteration as e:
print("g return value:", e.value)
break
18
有一种方法可以在一个函数中同时使用yield和return,这样你就可以返回一个值或者一个生成器。
这可能没有你想象中的那么简洁,但它确实能达到你想要的效果。
下面是一个例子:
def six(how_many=None):
if how_many is None or how_many < 1:
return None # returns value
if how_many == 1:
return 6 # returns value
def iter_func():
for count in range(how_many):
yield 6
return iter_func() # returns generator
101
没错,它仍然是一个生成器。这里的 return
几乎等同于抛出 StopIteration
。
PEP 255 中有详细说明:
说明:返回
生成器函数也可以包含这样的返回语句:
"return"
需要注意的是,在生成器的主体中,返回语句后面不能有表达式列表(当然,它们可以出现在生成器内部的非生成器函数中)。
当遇到返回语句时,控制流程就像在任何函数返回时一样,会执行相应的 finally 语句(如果有的话)。然后会抛出一个 StopIteration 异常,表示迭代器已经用完了。如果控制流在没有明确返回的情况下到达生成器的末尾,也会抛出 StopIteration 异常。
需要注意的是,返回的意思是“我完成了,没有什么有趣的东西可以返回”,这对于生成器函数和非生成器函数都是一样的。
另外,返回并不总是等同于抛出 StopIteration:它们的区别在于如何处理外部的 try/except 结构。例如,
>>> def f1(): ... try: ... return ... except: ... yield 1 >>> print list(f1()) []
因为在任何函数中,返回只是简单地退出,但
>>> def f2(): ... try: ... raise StopIteration ... except: ... yield 42 >>> print list(f2()) [42]
因为 StopIteration 会被一个简单的 "except" 捕获,就像捕获任何异常一样。