[PYTHON] 이상한 행동 : 목록 이해력의 람다
PYTHON이상한 행동 : 목록 이해력의 람다
파이썬 2.6에서 :
[x() for x in [lambda: m for m in [1,2,3]]]
결과 :
[3, 3, 3]
출력은 [1, 2, 3]이 될 것으로 기대합니다. 나는 비 목록 이해 (non list comprehension) 접근법으로도 똑같은 문제를 겪는다. 그리고 m을 다른 변수에 복사 한 후에도 마찬가지입니다.
내가 뭘 놓치고 있니?
해결법
-
==============================
1.람다가 m의 값을 기억하게하려면, 인자에 디폴트 값을 사용할 수있다.
람다가 m의 값을 기억하게하려면, 인자에 디폴트 값을 사용할 수있다.
[x() for x in [lambda m=m: m for m in [1,2,3]]] # [1, 2, 3]
이것은 기본값이 정의 시간에 한 번 설정되기 때문에 작동합니다. 이제 각 람다는 람다 실행 시간에 외부 범위에서 m 값을 찾는 대신 자체 기본값 인 m을 사용합니다.
-
==============================
2.발생하는 효과를 클로저라고하며, 로컬이 아닌 변수를 참조하는 함수를 정의 할 때이 함수는 자체 복사본을 가져 오는 대신 변수에 대한 참조를 유지합니다. 예를 들어, 코드를 람다 나 독해없이 동등한 버전으로 확장 할 것입니다.
발생하는 효과를 클로저라고하며, 로컬이 아닌 변수를 참조하는 함수를 정의 할 때이 함수는 자체 복사본을 가져 오는 대신 변수에 대한 참조를 유지합니다. 예를 들어, 코드를 람다 나 독해없이 동등한 버전으로 확장 할 것입니다.
inner_list = [] for m in [1, 2, 3]: def Lambda(): return m inner_list.append(Lambda)
따라서이 시점에서 inner_list에는 세 개의 함수가 있고 각 함수는 호출 될 때 m의 값을 반환합니다. 그러나 두드러진 점은 그들이 모두 똑같은 m을 보았다는 것입니다. m이 변하고 있더라도 훨씬 나중에 호출 될 때까지 결코 그것을 보지 않습니다.
outer_list = [] for x in inner_list: outer_list.append(x())
특히, 내부 목록은 외부 목록이 작성되기 전에 완전히 구성되기 때문에 m은 이미 마지막 값인 3에 도달했으며 세 함수 모두 동일한 값을 참조합니다.
-
==============================
3.길게 이야기하면, 당신은 이것을 원하지 않습니다. 좀 더 구체적으로, 당신이 겪고있는 것은 운영 문제의 순서입니다. 당신은 모두 m을 반환하는 3 개의 분리 된 람다를 만들고 있습니다 만, 그 중 아무도 즉시 호출되지 않습니다. 그런 다음, 외부 목록 이해에 도달하면 모두 m이라는 잔여 값은 내부 목록 이해력의 마지막 값인 3입니다.
길게 이야기하면, 당신은 이것을 원하지 않습니다. 좀 더 구체적으로, 당신이 겪고있는 것은 운영 문제의 순서입니다. 당신은 모두 m을 반환하는 3 개의 분리 된 람다를 만들고 있습니다 만, 그 중 아무도 즉시 호출되지 않습니다. 그런 다음, 외부 목록 이해에 도달하면 모두 m이라는 잔여 값은 내부 목록 이해력의 마지막 값인 3입니다.
- 댓글 용 -
>>> [lambda: m for m in range(3)] [<function <lambda> at 0x021EA230>, <function <lambda> at 0x021EA1F0>, <function <lambda> at 0x021EA270>]
그것들은 3 개의 분리 된 람다들입니다.
그리고 더 많은 증거로서 :
>>> [id(m) for m in [lambda: m for m in range(3)]] [35563248, 35563184, 35563312]
다시 세 가지 ID가 있습니다.
-
==============================
4.함수의 __closure__를보십시오. 3은 모두 동일한 셀 객체를 가리키며, 이는 외부 범위에서 m에 대한 참조를 유지합니다.
함수의 __closure__를보십시오. 3은 모두 동일한 셀 객체를 가리키며, 이는 외부 범위에서 m에 대한 참조를 유지합니다.
>>> print(*[x.__closure__[0] for x in [lambda: m for m in [1,2,3]]], sep='\n') <cell at 0x00D17610: int object at 0x1E2139A8> <cell at 0x00D17610: int object at 0x1E2139A8> <cell at 0x00D17610: int object at 0x1E2139A8>
unubtu의 답에 따라 함수가 키워드 인수로 m을 사용하지 않게하려면 각 반복에서 m을 평가하기 위해 추가 람다를 사용할 수 있습니다.
>>> [x() for x in [(lambda x: lambda: x)(m) for m in [1,2,3]]] [1, 2, 3]
-
==============================
5.개인적으로, 나는 이것을 더 우아한 해결책으로 생각한다. 람다 (Lambda)는 함수를 반환하므로 함수를 사용하고자한다면 그것을 사용해야합니다. 람다와 생성기에서 '익명'변수에 대해 동일한 기호를 사용하는 것은 혼란입니다. 따라서 제 예제에서는 다른 기호를 사용하여 더 명확하게 나타냅니다.
개인적으로, 나는 이것을 더 우아한 해결책으로 생각한다. 람다 (Lambda)는 함수를 반환하므로 함수를 사용하고자한다면 그것을 사용해야합니다. 람다와 생성기에서 '익명'변수에 대해 동일한 기호를 사용하는 것은 혼란입니다. 따라서 제 예제에서는 다른 기호를 사용하여 더 명확하게 나타냅니다.
>>> [ (lambda a:a)(i) for i in range(3)] [0, 1, 2] >>>
그것은 더 빠릅니다.
>>> timeit.timeit('[(lambda a:a)(i) for i in range(10000)]',number=10000) 9.231263160705566 >>> timeit.timeit('[lambda a=i:a for i in range(10000)]',number=10000) 11.117988109588623 >>>
지도만큼 빠르지는 않습니다.
>>> timeit.timeit('map(lambda a:a, range(10000))',number=10000) 5.746963977813721
(필자는이 테스트를 두 번 이상 실행했는데, 결과는 같았습니다. 파이썬 2.7에서 수행되었습니다. 결과는 파이썬 3에서 다릅니다. 두 목록의 이해도가 훨씬 더 비슷하고 훨씬 더 느리며 맵은 훨씬 빠릅니다.)
-
==============================
6.나는 그것도 알아 차렸다. 나는 람다 (lambda)가 단 한 번만 만들어 졌다고 결론을 내렸다. 따라서 실제로 내부 목록 이해력은 m의 마지막 값과 관련된 3 개의 indentical 함수를 제공합니다.
나는 그것도 알아 차렸다. 나는 람다 (lambda)가 단 한 번만 만들어 졌다고 결론을 내렸다. 따라서 실제로 내부 목록 이해력은 m의 마지막 값과 관련된 3 개의 indentical 함수를 제공합니다.
그것을 시도하고 요소의 id ()를 확인하십시오.
[참고 :이 답변은 정확하지 않습니다. 의견보기]
from https://stackoverflow.com/questions/7368522/weird-behavior-lambda-inside-list-comprehension by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 느린 스크립트가있는 전체 페이지로드까지 Selenium을 대기시키지 않으려면 어떻게합니까? (0) | 2018.10.08 |
---|---|
[PYTHON] 파이썬에서 함수를 "호출"한다는 것은 무엇을 의미합니까? [닫은] (0) | 2018.10.08 |
[PYTHON] 보다 큼 연산자 또는보다 작은 연산자를 사용하여 두 목록 비교 (0) | 2018.10.08 |
[PYTHON] PyCharm의 자동 완성이 내가 설치 한 라이브러리에서 작동하지 않는 이유는 무엇입니까? (0) | 2018.10.08 |
[PYTHON] 'is'연산자는 문자열을 공백으로 비교할 때 다르게 동작합니다. (0) | 2018.10.08 |