这是对 yield 语句的错误使用吗?
Is this a bad use of a `yield` statement?
我正在查看一位同事的代码,我觉得这是对 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)
我了解 preprocess_docs
中 yield
的用法,因此我可以 return 一个生成器,如果 docs
是一个大列表,这将很有帮助。但是我不明白 standardize_text
函数中 yield
的值。对我来说,return
语句会做同样的事情。
为什么 yield
会有用?
To me, a return
statement would do the exact same thing.
使用 return
与 yield
不同,如 .
中所述
使用 yield
,调用函数会得到 generator object:
>>> 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'
Is there a reason why that yield
would be useful?
在 standardize_text
函数中,不,不是真的。但是您的 preprocess_docs
函数实际上确实利用 yield
返回多个值:它 returns 一个生成器,对于 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
注意:在 Python 3 的 async
/await
之前,一些并发库使用 yield
的方式与现在使用 await
的方式相同。例如,Twisted's @inlineCallbacks
。我认为这与您的问题没有直接关系,但为了完整起见,我将其包括在内。
我正在查看一位同事的代码,我觉得这是对 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)
我了解 preprocess_docs
中 yield
的用法,因此我可以 return 一个生成器,如果 docs
是一个大列表,这将很有帮助。但是我不明白 standardize_text
函数中 yield
的值。对我来说,return
语句会做同样的事情。
为什么 yield
会有用?
To me, a
return
statement would do the exact same thing.
使用 return
与 yield
不同,如
使用 yield
,调用函数会得到 generator object:
>>> 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'
Is there a reason why that
yield
would be useful?
在 standardize_text
函数中,不,不是真的。但是您的 preprocess_docs
函数实际上确实利用 yield
返回多个值:它 returns 一个生成器,对于 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
注意:在 Python 3 的 async
/await
之前,一些并发库使用 yield
的方式与现在使用 await
的方式相同。例如,Twisted's @inlineCallbacks
。我认为这与您的问题没有直接关系,但为了完整起见,我将其包括在内。