我看了一位同事的代码,觉得这是对yield
语句的不必要使用。它是这样的:
def standardize_text(text: str):
pattern = r"ABC" # some regex
yield re.sub(pattern, "X", text)
def preprocess_docs(docs: List[str]):
for doc in docs:
yield standardize_text(doc)
我理解yield
在preprocess_docs
中的使用,这样我就可以返回生成器,如果docs
是一个大列表,这将很有帮助。但是我不理解standardize_text
函数中yield
的值。对我来说,return
语句也会起到完全相同的作用。
yield
有用的原因是什么?
对我来说,
return
语句会做完全相同的事情。
使用return
与yield
不同,正如ShadowRanger的评论中所解释的那样。
使用yield
,调用函数会得到一个生成器对象:
>>> standardize_text("ABCD")
<generator object standardize_text at 0x10561f740>
生成器可以产生多个结果(与使用return
的函数不同(。此生成器恰好生成一个项,即字符串(re.sub
的结果(。例如,您可以将生成器的结果收集到list()
中,或者只使用next()
:获取第一个结果
>>> list(standardize_text("ABCD"))
['XD']
>>> g = standardize_text("ABCD")
>>> next(g)
'XD'
>>> next(g) # raises StopIteration, indicating the generator has finished
如果我们将函数更改为使用return
:
def standardize_text(text: str):
pattern = r"ABC" # some regex
return re.sub(pattern, "X", text)
然后调用该函数只会得到单个结果——不需要list()
或next()
。
>>> standardize_text("ABCD")
'XD'
yield
有用的原因是什么?
在standardize_text
函数中,不,不是真的。但是preprocess_docs
函数实际上使用yield
返回多个值:它为docs
中的每个值返回一个生成器,其中包含一个结果。这些结果要么是生成器本身(在带有yield
的原始代码中(,要么是字符串(如果我们将standardize_text
更改为使用return
(。
def preprocess_docs(docs: List[str]):
for doc in docs:
yield standardize_text(doc)
# returns a generator because the implementation uses "yield"
>>> preprocess_docs(["ABCD", "AAABC"])
<generator object preprocess_docs at 0x10561f820>
# with standardize_text using "yield re.sub..."
>>> for x in preprocess_docs(["ABCD", "AAABC"]): print(x)
...
<generator object standardize_text at 0x1056cce40>
<generator object standardize_text at 0x1056cceb0>
# with standardize_text using "return re.sub..."
>>> for x in preprocess_docs(["ABCD", "AAABC"]): print(x)
...
XD
AAX
注意:在Python3的async
/await
之前,一些并发库使用yield
的方式与现在使用await
的方式相同。例如,Twisted的@inlineCallbacks
。我认为这与你的问题没有直接关系,但为了完整起见,我把它包括在内了。