질문을 단순화합시다. 밝히다:
def get_petters():
for animal in ['cow', 'dog', 'cat']:
def pet_function():
return "Mary pets the " + animal + "."
yield (animal, pet_function)
그런 다음 질문에서와 같이 다음을 얻습니다.
>>> for name, f in list(get_petters()):
... print(name + ":", f())
cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.
그러나 list()
첫 번째 생성을 피한다면 :
>>> for name, f in get_petters():
... print(name + ":", f())
cow: Mary pets the cow.
dog: Mary pets the dog.
cat: Mary pets the cat.
무슨 일이야? 이 미묘한 차이가 결과를 완전히 바꾸는 이유는 무엇입니까?
를 살펴보면 list(get_petters())
변경되는 메모리 주소에서 우리가 실제로 수행하는 세 가지 다른 기능이 있음이 분명합니다.
>>> list(get_petters())
[('cow', <function get_petters.<locals>.pet_function at 0x7ff2b988d790>),
('dog', <function get_petters.<locals>.pet_function at 0x7ff2c18f51f0>),
('cat', <function get_petters.<locals>.pet_function at 0x7ff2c14a9f70>)]
그러나 cell
이러한 함수가 바인딩되는에 대해 살펴보십시오 .
>>> for _, f in list(get_petters()):
... print(f(), f.__closure__)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
Mary pets the cat. (<cell at 0x7ff2c112a9d0: str object at 0x7ff2c3f437f0>,)
>>> for _, f in get_petters():
... print(f(), f.__closure__)
Mary pets the cow. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a95670>,)
Mary pets the dog. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c1a952f0>,)
Mary pets the cat. (<cell at 0x7ff2b86b5d00: str object at 0x7ff2c3f437f0>,)
두 루프 모두 cell
객체는 반복 동안 동일하게 유지됩니다. 그러나 예상대로 str
참조 하는 특정 사항 은 두 번째 루프에서 다릅니다. cell
객체를 지칭 animal
할 때 생성되는, get_petters()
호출된다. 그러나 생성기 함수가 실행될 때 참조 animal
하는 str
객체를 변경 합니다 .
첫 번째 루프에서 각 반복 동안 모든 f
s를 생성 하지만 생성기 get_petters()
가 완전히 고갈되고 list
함수가 이미 생성 된 후에 만 호출합니다 .
두 번째 루프에서 각 반복 동안 get_petters()
생성기를 일시 중지하고 f
각 일시 중지 후에 호출 합니다. 따라서 animal
생성기 기능이 일시 중지 된 시점에 의 값을 검색하게 됩니다.
@Claudiu가 비슷한 질문 에 대한 답변을 넣었 듯이 :
세 개의 개별 함수가 생성되지만 각각 정의 된 환경 (이 경우에는 전역 환경 (또는 루프가 다른 함수 내부에 배치 된 경우 외부 함수의 환경))이 종료됩니다. 하지만 이것은 정확히 문제입니다.이 환경에서는 animal
변이되고, 클로저는 모두 같은 것을 참조합니다 animal
.
[편집자 주 : i
가로 변경되었습니다 animal
.]
for animal in ['cat', 'dog', 'cow']
... 누군가가 와서 이것을 설명 할 것이라고 확신합니다-그것은 Python gotcha 중 하나입니다 :)