"yield from"문을 Python 2.7 코드로 변환
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
당신이 당신의 수율의 결과를 사용하지 않는 경우 * 당신은 할 수 항상 이 설정 :
yield from foo
… 이것으로 :
for bar in foo:
yield bar
성능 비용이있을 수 있지만 ** 의미 상 차이는 없습니다.
부모 재귀가 yield from call과 함께 두 반쪽을 함께 사용하도록 두 반쪽 (위쪽과 아래쪽)의 항목이 하나의 목록에 서로 추가됩니까?
아니! 반복기와 생성기의 요점은 실제 목록을 작성하고 함께 추가하지 않는다는 것입니다.
하지만 그 효과 는 비슷합니다. 하나에서 양보 한 다음 다른 사람에서 양보합니다.
위쪽 절반과 아래쪽 절반을 "지연 목록"으로 생각하면 더 큰 "지연 목록"을 생성하는 "지연 추가"로 생각할 수 있습니다. 당신이 호출하는 경우 그리고 list
부모 함수의 결과에, 물론 당신은 것 실제 얻을 list
함께 작업을 완료 더라면 당신이받은 것 두 목록 추가에 해당의 그 yield list(…)
대신을 yield from …
.
그러나 나는 그것을 다른 방향으로 생각하는 것이 더 쉽다고 생각합니다 : 그것이하는 일은 for
루프가 하는 것과 똑같습니다 .
두 반복자를 변수에 저장하고을 itertools.chain(upper, lower)
반복하면 첫 번째 반복을 반복 한 다음 두 번째 반복을 반복하는 것과 같습니다. 여기에 차이가 없습니다. 실제로 다음 chain
과 같이 구현할 수 있습니다.
for arg in *args:
yield from arg
* PEP 342에send
설명 된대로 생성기가 호출자에게 산출하는 값이 아니라 생성기 내에서 yield 표현식 자체의 값 ( 메소드를 사용하여 호출자로부터 생성됨 ) . 당신은 당신의 예제에서 이것을 사용하지 않습니다. 그리고 나는 당신이 당신의 실제 코드에 있지 않다고 확신합니다. 그러나 코 루틴 스타일 코드는 종종 표현식 의 값을 사용합니다 . 예제는 PEP 3156 을 참조하십시오 . 이러한 코드는 일반적으로 Python 3.3 생성기의 다른 기능, 특히 도입 된 동일한 PEP 380 의 새로운 기능에 의존합니다.yield from
StopIteration.value
yield from
-따라서 다시 작성해야합니다. 그러나 그렇지 않다면 PEP를 사용하면 완전히 끔찍한 지저분한 등가물을 보여줄 수 있으며 물론 신경 쓰지 않는 부분을 줄일 수 있습니다. 식의 값을 사용하지 않으면 위의 두 줄로 축소됩니다.
** 크지 않고 Python 3.3을 사용하거나 코드를 완전히 재구성하는 것 외에는 할 수있는 일이 없습니다. 목록 이해를 Python 1.5 루프로 번역하는 것과 똑같은 경우이거나 버전 XY에 새로운 최적화가 있고 이전 버전을 사용해야하는 다른 경우입니다.
for 루프로 대체하십시오.
yield from range(L[start] + 1, L[end])
==>
for i in range(L[start] + 1, L[end]):
yield i
요소에 대해서도 동일합니다.
yield from missing_elements(L, index, end)
==>
for el in missing_elements(L, index, end):
yield el
방금이 문제를 발견했으며 반환 값 이 필요했기 때문에 사용이 조금 더 어려웠습니다 yield from
.
result = yield from other_gen()
이것은 단순한 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
바라건대 이것은 같은 문제를 겪는 사람들에게 도움이 될 것입니다. :)
yield from
Python 2.x에서 Python 3.x 구조 를 에뮬레이트하는 방법을 찾은 것 같습니다 . 효율적이지 않고 약간 엉망이지만 여기에 있습니다.
import types
def inline_generators(fn):
def inline(value):
if isinstance(value, InlineGenerator):
for x in value.wrapped:
for y in inline(x):
yield y
else:
yield value
def wrapped(*args, **kwargs):
result = fn(*args, **kwargs)
if isinstance(result, types.GeneratorType):
result = inline(_from(result))
return result
return wrapped
class InlineGenerator(object):
def __init__(self, wrapped):
self.wrapped = wrapped
def _from(value):
assert isinstance(value, types.GeneratorType)
return InlineGenerator(value)
용법:
@inline_generators
def outer(x):
def inner_inner(x):
for x in range(1, x + 1):
yield x
def inner(x):
for x in range(1, x + 1):
yield _from(inner_inner(x))
for x in range(1, x + 1):
yield _from(inner(x))
for x in outer(3):
print x,
출력을 생성합니다.
1 1 1 2 1 1 2 1 2 3
누군가 이것이 도움이 될 수 있습니다.
알려진 문제 : PEP 380에 설명 된 send () 및 다양한 코너 케이스에 대한 지원이 부족합니다. 추가 될 수 있으며 작업이 완료되면 항목을 편집하겠습니다.
Python 2 구문 버전을 구성하기 위해 pep-380 의 정의를 사용하는 것은 어떻습니까?
진술 :
RESULT = yield from EXPR
의미 상 다음과 같습니다.
_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
생성기에서 문 :
return value
의미 상 동등하다
raise StopIteration(value)
except that, as currently, the exception cannot be caught by except
clauses within the returning generator.
The StopIteration exception behaves as though defined thusly:
class StopIteration(Exception):
def __init__(self, *args):
if len(args) > 0:
self.value = args[0]
else:
self.value = None
Exception.__init__(self, *args)
I've found using resource contexts (using the python-resources module) to be an elegant mechanism for implementing subgenerators in Python 2.7. Conveniently I'd already been using the resource contexts anyway.
If in Python 3.3 you would have:
@resources.register_func
def get_a_thing(type_of_thing):
if type_of_thing is "A":
yield from complicated_logic_for_handling_a()
else:
yield from complicated_logic_for_handling_b()
def complicated_logic_for_handling_a():
a = expensive_setup_for_a()
yield a
expensive_tear_down_for_a()
def complicated_logic_for_handling_b():
b = expensive_setup_for_b()
yield b
expensive_tear_down_for_b()
In Python 2.7 you would have:
@resources.register_func
def get_a_thing(type_of_thing):
if type_of_thing is "A":
with resources.complicated_logic_for_handling_a_ctx() as a:
yield a
else:
with resources.complicated_logic_for_handling_b_ctx() as b:
yield b
@resources.register_func
def complicated_logic_for_handling_a():
a = expensive_setup_for_a()
yield a
expensive_tear_down_for_a()
@resources.register_func
def complicated_logic_for_handling_b():
b = expensive_setup_for_b()
yield b
expensive_tear_down_for_b()
Note how the complicated-logic operations only require the registration as a resource.
참고URL : https://stackoverflow.com/questions/17581332/converting-yield-from-statement-to-python-2-7-code
'development' 카테고리의 다른 글
java.util.Date 내부 참조를 노출하지 않도록 복제 또는 복사 (0) | 2020.11.21 |
---|---|
인앱 결제 테스트 : "게시자가이 항목을 구매할 수 없습니다." (0) | 2020.11.21 |
파이썬에서 % timeit은 무엇입니까? (0) | 2020.11.21 |
PowerShell의 기본 출력 인코딩을 UTF-8로 변경 (0) | 2020.11.21 |
테스트를 위해 DB를 시뮬레이션하는 방법 (Java)? (0) | 2020.11.21 |