2012-10-29 4 views
2

여기에 무슨 일이 일어나고 있는지 궁금합니다. 발전기와 코 루틴을 아는 사람이이 코드를 잘 설명 할 수 있습니까?파이썬 :이 생성기로 무슨 일이 일어나는지 이해하지 못합니다.

def b(): 
    for i in range(5): 
     yield i 
     x = (yield) 
     print(x) 

def a(): 
    g = b() 
    next(g) 
    for i in range(4): 
     g.send(5) 
     print(next(g)) 

a() 
출력

None 
1 
None 
2 
None 
3 
None 
4 

하지만 라인 3과 4의 주위에 전환 할 때 : 선 yield ix = (yield)을, 나는 다음을 얻을.

5 
None 
5 
None 
5 
None 
5 
None 

yield 함수를 사용하여 동일한 함수에서 값을 보내고 보내는 데 문제가 있다고 생각합니다. 파이썬에서는 이것이 불가능합니까?

나는 coroutines를 사용하는 몇 가지 프로그램을 성공적으로 작성하여 작동 방식에 익숙하지만이 코드 스 니펫이 작동하는 방식에 대해 혼란 스럽습니다. 이것에 대한 통찰력은 인정 될 것이다.

감사

편집 : 감사 BrenBarn과 답변 unutbu. 여기서 일어나는 일은 문제를 그렇게 확장 할 때 더 합리적입니다.

def b(): 
    for i in range(5): 
     yield i 
     x = yield None 

def a(): 
    g = b() 
    print('* got', g.send(None)) 
    for i in range(4): 
     print('+ got', g.send(5)) 
     print('- got', g.send(None)) 

a() 

답변

4

꽤 기본적으로 당신이 요구하는지 무엇을 얻을 수 있지만,하지 않습니다 당신이 send를 사용할 때, 당신이 보내는 값으로 평가하는 발전기에서 가장 최근에 도달 수율 표현됩니다. send은 생성자를 다음 yield으로 진행합니다. 한 가지 분명한 것은 발전기 내부에 x의 값을 인쇄하고 next(g) 값을 b 안에 인쇄하지만 발전기는 g.send(5)의 값을 산출하고 인쇄하지 않는다는 것입니다. 첫 번째 경우

는 첫 번째 sendb 내부에 5로 평가하는 yield i 문을 유발하지만 아무것도하지 않는, 그래서 당신은 b 내부에이 값을 (당신은 아무것도에 yield i을 할당하지 않음) 사용하지 마십시오. 또한 send(5)을 수행하면 발전기가 없음 (x = (yield) 줄에서)을 산출하지만 인쇄하지 않아서 모를 수 있습니다. 그런 다음 next(g)으로 발전기를 다시 전진하십시오. 가장 최근에 도달 한 수익률은 x = yield이지만 next(g)은 아무 값도 전달하지 않으므로 x은 없음으로 설정됩니다.

두 번째 경우에는 통화의 패리티가 취소됩니다. 이제 첫 번째 sendx = yield 줄로 보내 지므로 x은 5로 설정됩니다.이 send도 루프 값을 b으로 산출하지만이 값은 a에서 무시하고 인쇄하지 마십시오. 그런 다음 next(g)을 인쇄합니다. 이는 없음입니다. 각 후속 송신에서 b은 항상의 값을 인쇄합니다. 이는 항상 보내는 값이기 때문에 항상 0이므로 a다음으로 값을 산출합니다. 이는 항상 x = yield의 값이기 때문에 없음입니다.

"yield 문을 사용하여 동일한 함수에서 값을 받고 보내는 데"무슨 뜻인지 알 수 없습니다. 확실히 이것을 할 수는 있지만 다음을 깨달아야합니다. a) next(g)으로 전화를 걸어도 값 (없음)이 계속 전송됩니다. b) g.send(5)으로 전화하면 값이 계속 산출됩니다.이 프로그램을 통해 라인 별 단계로 traceit를 사용

+0

감사합니다. g.send (5) 결과를 출력하지 않아서 혼란 스러웠습니다. 나는 또한'x = yield '가'x = yield None'과 같은 것을 잊었다. –

5

: 파이썬은 다음 None를 인쇄하는 이유

import sys 
import linecache 

class SetTrace(object): 
    ''' 
    with SetTrace(monitor): 
     ... 
    ''' 
    def __init__(self, func): 
     self.func = func 
    def __enter__(self): 
     sys.settrace(self.func) 
     return self 
    def passit(self, frame, event, arg): 
     return self.passit 
    def __exit__(self, ext_type, exc_value, traceback): 
     sys.settrace(self.passit) 

def traceit(frame, event, arg): 
    ''' 
    http://www.dalkescientific.com/writings/diary/archive/2005/04/20/tracing_python_code.html 
    ''' 
    if event == "line": 
     lineno = frame.f_lineno 
     filename = frame.f_globals["__file__"] 
     if (filename.endswith(".pyc") or 
      filename.endswith(".pyo")): 
      filename = filename[:-1] 
     name = frame.f_globals["__name__"] 
     line = linecache.getline(filename, lineno) 
     print("%s # %s:%s" % (line.rstrip(), name, lineno,)) 
    return traceit  

def b(): 
    for i in range(5): 
     yield i 
     x = (yield) 
     print(x) 

def a(): 
    g = b()      
    next(g) 
    for i in range(4): 
     g.send(5) 
     print(next(g)) 

with SetTrace(traceit): 
    a()   

우리는 오른쪽에 의견

g = b() # __main__:44 
next(g) # __main__:45     # runs b until you get to a yield 
for i in range(5): # __main__:38 
    yield i # __main__:39    # stop before the yield; resume a 
    ^
for i in range(4): # __main__:46 
    g.send(5) # __main__:47   # resume b; (yield i) expression evals to 5 then thrown away 
    x = (yield) # __main__:40   # stop before yield; resume a 
     ^
    print(next(g)) # __main__:48  # next(g) called; resume b; print not called yet 
    print(x) # __main__:41   # next(g) causes (yield) to evaluate to None 
None 
for i in range(5): # __main__:38 
    yield i # __main__:39    # yield 1; resume a; `print(next(g))` prints 1 
1 
for i in range(4): # __main__:46 
    g.send(5) # __main__:47   # resume b; (yield i) expression evals to 5 then thrown away 

를 얻을 수 (위) 설명 1. 당신이 그것을 멀리 얻는다면, 나는 당신이 None, 2, 등을 얻는 이유가 분명하다고 생각합니다. 그것은 i에 대해 다른 값으로 다시 한번 같은 이야기입니다.

x = (yield)yield i이 반대 인 다른 시나리오도 마찬가지로 분석 할 수 있습니다.

+1

와우, 전 트레이시트를 본 적이 없었어요. 아주 멋지다. –

관련 문제