2012-09-07 2 views
5

표현으로 수율을 이해하려고하고 나는 그들이 어떻게 작동하는지 이해하는 것이 완전히 확실하지 않다 (some reference material) : generator.send이처럼내가 발전기, 발전기 표정으로 주위를 연주 해요

>>> a = (x for x in range(10)) 
>>> next(a) 
0 
>>> next(a) 
1 
>>> a.send(-1) 
2 
>>> next(a) 
3 

그래서 그것은 본다 무시. 즉 수있는 의미 (내 생각) 전송 된 정보를 잡을 수있는 명시 적 yield 표현이 없기 때문에 ... 그러나

,

>>> a = ((yield x) for x in range(10)) 
>>> next(a) 
0 
>>> print next(a) 
None 
>>> print next(a) 
1 
>>> print next(a) 
None 
>>> a.send(-1) #this send is ignored, Why? ... there's a yield to catch it... 
2 
>>> print next(a) 
None 
>>> print next(a) 
3 
>>> a.send(-1) #this send isn't ignored 
-1 

내가이 밖에 꽤 멀리 이해하고, (현재) I하게

나는이 다양한 생성기 메서드가 어떻게 작동하는지 (그리고 생성기식이 일반적으로 어떻게 작동하는지) 알아 내려고 노력하고있다. 두 번째 예제가 합리적인 값을주고 None을 번갈아 표시하는 이유는 무엇입니까? 또한, 왜 내 generator.send 중 하나가 무시되었는데 다른 하나는 무시되었다고 설명 할 수 있습니까?

+1

이 링크가 도움이되는지 확인하십시오 ... http://stackoverflow.com/questions/231767/the-python-yield-keyword-explained –

답변

3

여기서 혼란은 발전기 표현이 숨겨진 yield을 수행하고 있다는 것입니다. 여기 기능의 형태 :

def foo(): 
    for x in range(10): 
     yield (yield x) 

당신이 .send()을 수행 할 때 무슨 일 x을 산출하는 내부 yield x이 실행됩니다이다. 그런 다음 표현식이 .send의 값으로 평가되고 다음 수익률이 산출됩니다. 여기 명확 형태 :

def foo(): 
    for x in range(10): 
     sent_value = (yield x) 
     yield sent_value 

따라서 출력은 매우 예측 :

>>> a = foo() 
#start it off 
>>> a.next() 
0 
#execution has now paused at "sent_value = ?" 
#now we fill in the "?". whatever we send here will be immediately yielded. 
>>> a.send("yieldnow") 
'yieldnow' 
#execution is now paused at the 'yield sent_value' expression 
#as this is not assigned to anything, whatever is sent now will be lost 
>>> a.send("this is lost") 
1 
#now we're back where we were at the 'yieldnow' point of the code 
>>> a.send("yieldnow") 
'yieldnow' 
#etc, the loop continues 
>>> a.send("this is lost") 
2 
>>> a.send("yieldnow") 
'yieldnow' 
>>> a.send("this is lost") 
3 
>>> a.send("yieldnow") 
'yieldnow' 

EDIT : 실시 예 사용. 지금까지 본 것 중에 가장 멋진 것 중 하나가 꼬인 것입니다. inlineCallbacks 기능. 그것을 설명하는 기사는 See here입니다. 그 중 하나는 스레드에서 실행되는 함수를 생성 할 수 있으며 함수가 완료되면 함수의 결과를 코드로 다시 보냅니다. 따라서 많은 함수를 많은 곳에서 쓸 필요없이 직선적이고 직관적 인 방식으로 스레드에 크게 의존하는 코드를 작성할 수 있습니다.

.send이 잠재적 인 유스 케이스와 함께 작동하는 이유에 대한 자세한 내용은 PEP 342을 참조하십시오. 제공된 트위스트 예는이 변경이 제공하는 비동기 입출력에 대한 장점입니다.

+0

감사합니다. 매우 도움이되었습니다. – mgilson

+0

흠 ... 당신이'[ 'a', 'c', 'e']'와'[ 'b', 'd', f ']'리스트를'[' a ','b ','c ','d ','e ','f ']'... – mgilson

+0

@mgilson : 당신은 또한'+'를 사용할 수 있습니다. 나는 좋은 유스 케이스에서 곧 내 대답을 업데이트 할 것이다. – Claudiu

2

이 발전기로 변환 : 보내는 두 번째 통화의

for i in xrange(10): 
    x = (yield i) 
    yield x 

결과()/다음()는 수익률 중 하나의 결과에 아무것도 할 수 없기 때문에, 무시됩니다.

2

실제로 두 소스에서 생성하기 때문에 조금 혼란스러워합니다. 생성자 표현 (... for x in range(10))은 하나의 생성자이지만 yield으로 다른 소스를 만듭니다. list(a)을 입력하면 [0, None, 1, None, 2, None, 3, None, 4, None, 5, None, 6, None, 7, None, 8, None, 9, None]이 표시됩니다.

코드는 다음과 동등하다 :

>>> def gen(): 
...  for x in range(10): 
...   yield (yield x) 

만 내부 수율 ("수율 X")은 상기 발전기에 --- 이것은 외부 수율 값으로 사용된다 "사용"이다. 따라서이 생성기는 범위의 값을 산출하는 사이에서 앞뒤로 반복하고 그 산출물에 "전송 된"것이 무엇이든 산출합니다. 내적 수익률에 무언가를 보내면 다시 얻게되지만, 짝수 반복을 보내면 외근 률로 보내고 무시됩니다.

+0

나는 2 개의 생성자를 만들지 않았다 - 나는 2 개의 생성 문을 가진 1 개의 생성자를 만들었다 ;-) (외관상으로는) – mgilson

+0

당신이 옳다는 것은 당신이 두 가지 근원으로부터 생성하고 있다고 말하는 좋은 방법이다. – BrenBarn

+0

'yield '가 표현 (진술이 아님)이라는 것을 깨달았을 때 그것은 나를 그냥 날려 버렸습니다. 그래서 나는 그 지식으로 실제로 할 수있는 것을 알아 내기 위해 놀기 시작했습니다. ... – mgilson

-1

실제로 - send 메서드는 명시 적으로 작성한 공동 루틴의 결과 인 생성기 개체와 함께 작동합니다. 생성기 표현에서 어떤 의미를 얻는 것은 어렵습니다.

- 편집 - 내가 이전에이를 작성했지만, 발전기 식 내부 수율이 구현에서 예측 가능한대로, incorrecct입니다 - 어떤 PEP에 언급되지 않은 있지만.

generator expressions are not meant to have the yield keyword - I am not shure the behavior is even defined in this case. We could think a little and get to what is happening on your expression, to meet from where those "None"s are coming from. However, assume that as a side effect of how the yield is implemented in Python (and probably it is even implementation dependent), not as something that should be so.

간단한 방식으로 생성 식의 정확한 형태는이다

(<expr> for <variable> in <sequence> [if <expr>]) 

그래서 <expr><sequence:의 각 값에 대한 평가 -뿐만 yield uneeded 그대로는 안 그걸 써.

모두 yieldsend 방법은 전체 공동 루틴에 사용되는 의미, 뭔가 같은 :

def doubler(): 
    value = 0 
    while value < 100: 
     value = 2 * (yield value) 

그리고 당신이 원하는 사용할 수 있습니다

>>> a = doubler() 
>>> # Next have to be called once, so the code will run up to the first "yield" 
... 
>>> a.next() 
0 
>>> a.send(10) 
20 
>>> a.send(20) 
40 
>>> a.send(23) 
46 
>>> a.send(51) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration 
>>> 
+0

아래로 유권자의 관심을 돌리시겠습니까? – jsbueno

+1

예. "생성자 표현식에는 yield 키워드가 없으므로이 경우에도 동작을 정의 할 수 있습니다." 그것은 완벽하게 정의되어 있습니다. [this pastebin] (http://pastebin.com/Yq6XeTUg)을 참조하십시오. 그것은 조금 이상하지만, 이해가됩니다. – Claudiu

+0

None은 구현에 의존하지 않는다. Nones (yield를 None으로 보낸) Nones를 호출했다. – Claudiu

0

당신이 쓴 발전기는 더 자세한 정보와 동일 :

def testing(): 
    for x in range(10): 
      x = (yield x) 
      yield x 

e, 생성자 표현식에 내재 된 두 번째 yield은 전달한 값을 저장하지 않으므로 생성자 실행이 차단 된 위치에 따라 send이 작동하거나 작동하지 않을 수 있습니다.

관련 문제