vka*_*l11 66 python yield generator python-2.x yield-from
我在Python 3.2中有一个代码,我想在Python 2.7中运行它.我确实转换了它(已经把missing_elements两个版本的代码都放了)但我不确定这是否是最有效的方法.基本上如果yield from在missing_element功能的上半部分和下半部分有两个如下所示的调用会发生什么?两个部分(上部和下部)中的条目是否在一个列表中相互附加,以便父级递归函数与yield from调用一起使用并将两个部分一起使用?
def missing_elements(L, start, end): # Python 3.2
if end - start <= 1:
if L[end] - L[start] > 1:
yield from range(L[start] + 1, L[end])
return
index = start + (end - start) // 2
# is the lower half consecutive?
consecutive_low = L[index] == L[start] + (index - start)
if not consecutive_low:
yield from missing_elements(L, start, index)
# is the upper part consecutive?
consecutive_high = L[index] == L[end] - (end - index)
if not consecutive_high:
yield from missing_elements(L, index, end)
def main():
L = [10, 11, 13, 14, 15, 16, 17, 18, 20]
print(list(missing_elements(L, 0, len(L)-1)))
L = range(10, 21)
print(list(missing_elements(L, 0, len(L)-1)))
def missing_elements(L, start, end): # Python 2.7
return_list = []
if end - start <= 1:
if L[end] - L[start] > 1:
return range(L[start] + 1, L[end])
index = start + (end - start) // 2
# is the lower half consecutive?
consecutive_low = L[index] == L[start] + (index - start)
if not consecutive_low:
return_list.append(missing_elements(L, start, index))
# is the upper part consecutive?
consecutive_high = L[index] == L[end] - (end - index)
if not consecutive_high:
return_list.append(missing_elements(L, index, end))
return return_list
Run Code Online (Sandbox Code Playgroud)
aba*_*ert 83
如果您不使用收益率的结果,*您可以随时将其转为:
yield from foo
Run Code Online (Sandbox Code Playgroud)
......进入这个:
for bar in foo:
yield bar
Run Code Online (Sandbox Code Playgroud)
可能存在性能成本,**但是从来没有语义差异.
来自两半(上部和下部)的条目是否在一个列表中相互附加,以便父递归函数具有来自调用的收益并将两个一起使用?
没有!迭代器和生成器的重点在于您不构建实际列表并将它们附加在一起.
但效果是相似的:你只从一个产出,然后从另一个产出.
如果你认为上半部分和下半部分是"懒惰列表",那么是的,你可以把它想象成一个"懒惰的附加",创建一个更大的"懒惰列表".如果你调用list父函数的结果,你当然会得到一个实际list的相当于将你可能得到的两个列表附加在一起yield list(…)而不是yield from ….
但我认为反过来更容易想到它:它的作用与for循环完全相同.
如果你将两个迭代器保存到变量中并循环itertools.chain(upper, lower),那就像循环第一个然后循环遍历第二个一样,对吧?这里没什么区别.实际上,您可以实现chain:
for arg in *args:
yield from arg
Run Code Online (Sandbox Code Playgroud)
*不是生成器对其调用者产生的值,即生成器中的yield表达式本身的值(来自使用该send方法的调用者),如PEP 342中所述.你没有在你的例子中使用这些.而且我愿意打赌你不是真正的代码.但是,协程式代码通常使用yield from表达式的值- 请参阅PEP 3156作为示例.这样的代码通常依赖于Python 3.3生成器的其他功能 - 特别是StopIteration.value来自引入的相同PEP 380的新功能yield from - 所以它必须重写.但如果没有,你可以使用PEP也向你展示完全可怕的杂乱等同物,你当然可以减少你不关心的部分.如果你不使用表达式的值,它会减少到上面的两行.
**不是很大,除了使用Python 3.3或完全重构代码之外,你无能为力.这与将列表推导转换为Python 1.5循环完全相同,或者在版本XY中进行新优化并且您需要使用旧版本时的任何其他情况.
我只是碰到这个问题,我使用的是一个有点困难,因为我需要返回值的yield from:
result = yield from other_gen()
Run Code Online (Sandbox Code Playgroud)
这不能表示为一个简单的for循环,但可以用这个重现:
_iter = iter(other_gen())
try:
while True: #broken by StopIteration
yield next(_iter)
except StopIteration as e:
if e.args:
result = e.args[0]
else:
result = None
Run Code Online (Sandbox Code Playgroud)
希望这会帮助遇到同样问题的人。:)
如何使用pep-380中的定义来构建 Python 2 语法版本:
该声明:
RESULT = yield from EXPR
Run Code Online (Sandbox Code Playgroud)
在语义上等同于:
_i = iter(EXPR)
try:
_y = next(_i)
except StopIteration as _e:
_r = _e.value
else:
while 1:
try:
_s = yield _y
except GeneratorExit as _e:
try:
_m = _i.close
except AttributeError:
pass
else:
_m()
raise _e
except BaseException as _e:
_x = sys.exc_info()
try:
_m = _i.throw
except AttributeError:
raise _e
else:
try:
_y = _m(*_x)
except StopIteration as _e:
_r = _e.value
break
else:
try:
if _s is None:
_y = next(_i)
else:
_y = _i.send(_s)
except StopIteration as _e:
_r = _e.value
break
RESULT = _r
Run Code Online (Sandbox Code Playgroud)
在生成器中,语句:
return value
Run Code Online (Sandbox Code Playgroud)
在语义上等价于
raise StopIteration(value)
Run Code Online (Sandbox Code Playgroud)
except不同之处在于,目前,返回生成器中的子句无法捕获异常。
StopIteration 异常的行为就像这样定义的:
class StopIteration(Exception):
def __init__(self, *args):
if len(args) > 0:
self.value = args[0]
else:
self.value = None
Exception.__init__(self, *args)
Run Code Online (Sandbox Code Playgroud)
用 for 循环替换它们:
yield from range(L[start] + 1, L[end])
==>
for i in range(L[start] + 1, L[end]):
yield i
Run Code Online (Sandbox Code Playgroud)
元素也一样:
yield from missing_elements(L, index, end)
==>
for el in missing_elements(L, index, end):
yield el
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
26635 次 |
| 最近记录: |