내가 깊이에 더 그것을 설명하려고합니다.
당신이
i = 0
f = lambda: i
당신이 (람다은 본질적으로 기능입니다) 포위 스코프의 i
변수에 액세스하는 함수를 만드는 작업을 수행합니다.
내부적으로는 i
을 포함하는 소위 폐쇄가 있습니다. 느슨하게 말해서, 서로 다른 시점에서 다른 값을 가질 수있는 실제 변수에 대한 포인터의 일종입니다.
def a():
# first, yield a function to access i
yield lambda: i
# now, set i to different values successively
for i in range(100): yield
g = a() # create generator
f = next(g) # get the function
f() # -> error as i is not set yet
next(g)
f() # -> 0
next(g)
f() # -> 1
# and so on
f.func_closure # -> an object stemming from the local scope of a()
f.func_closure[0].cell_contents # -> the current value of this variable
여기서, i
의 모든 값은 - 그 시간에 - 상기 클로저에 저장된다. 기능이 f()
인 경우 필요합니다. 그것은 거기에서 그들을 얻는다.
당신은 분해 명부에 그 차이를 볼 수 있습니다
이 말했다 기능 a()
및 f()
을 다음과 같이 분해 :
>>> dis.dis(a)
2 0 LOAD_CLOSURE 0 (i)
3 BUILD_TUPLE 1
6 LOAD_CONST 1 (<code object <lambda> at 0xb72ea650, file "<stdin>", line 2>)
9 MAKE_CLOSURE 0
12 YIELD_VALUE
13 POP_TOP
3 14 SETUP_LOOP 25 (to 42)
17 LOAD_GLOBAL 0 (range)
20 LOAD_CONST 2 (100)
23 CALL_FUNCTION 1
26 GET_ITER
>> 27 FOR_ITER 11 (to 41)
30 STORE_DEREF 0 (i)
33 LOAD_CONST 0 (None)
36 YIELD_VALUE
37 POP_TOP
38 JUMP_ABSOLUTE 27
>> 41 POP_BLOCK
>> 42 LOAD_CONST 0 (None)
45 RETURN_VALUE
>>> dis.dis(f)
2 0 LOAD_DEREF 0 (i)
3 RETURN_VALUE
비교하는
>>> def b():
... for i in range(100): yield
>>> dis.dis(b)
2 0 SETUP_LOOP 25 (to 28)
3 LOAD_GLOBAL 0 (range)
6 LOAD_CONST 1 (100)
9 CALL_FUNCTION 1
12 GET_ITER
>> 13 FOR_ITER 11 (to 27)
16 STORE_FAST 0 (i)
19 LOAD_CONST 0 (None)
22 YIELD_VALUE
23 POP_TOP
24 JUMP_ABSOLUTE 13
>> 27 POP_BLOCK
>> 28 LOAD_CONST 0 (None)
31 RETURN_VALUE
과 같은 기능
b()
에
루프의 주요 차이점은
입니다.
>> 13 FOR_ITER 11 (to 27)
16 STORE_FAST 0 (i)
대 a()
에서
>> 27 FOR_ITER 11 (to 41)
30 STORE_DEREF 0 (i)
b()
에서하십시오 cell
객체 (폐쇄)에서 STORE_DEREF
상점, STORE_FAST
동안 (아마) 조금 더 빠르게 작동하는 "정상"변수를 사용합니다.하나는 위의 LOAD_DEREF
를 사용하면서 여기
>>> dis.dis(lambda: i)
1 0 LOAD_GLOBAL 0 (i)
3 RETURN_VALUE
당신이하는 LOAD_GLOBAL
있습니다
뿐만 아니라 람다는 차이가 있습니다. 후자 역시 폐쇄를위한 것이다.
완전히 lambda i=i: i
을 잊었습니다. 당신은 기본 매개 변수 값이있는 경우
, 그것은 완전히 다른 경로를 통해 기능에 영향을 찾습니다
>>> i = 42
>>> f = lambda i=i: i
>>> dis.dis(f)
1 0 LOAD_FAST 0 (i)
3 RETURN_VALUE
:
i
의 현재 값은 기본 매개 변수를 통해 방금 만든 함수에 전달됩니다
이렇게하면 함수는 f()
으로 호출됩니다. 누락 된 인수가 있음을 감지하고 해당 매개 변수를 기본값으로 채 웁니다. 이 모든 것은 함수가 호출되기 전에 발생합니다. 함수 내에서 값을 가져 와서 반환한다는 것을 알 수 있습니다.
그리고 또 다른 방법으로 작업을 수행 할 수 있습니다. 람다를 값으로 사용하는 것처럼 그냥 사용하십시오 : lambda i: i
. 이것을 호출하면 누락 된 인수에 대해 불평합니다.
하지만 functools.partial
의 사용과 그 대처 할 수 있습니다
ff = [functools.partial(lambda i: i, x) for x in range(100)]
ff[12]()
ff[54]()
이 래퍼는 호출과 인수의 수를 가져옵니다이 전달 될 수 있습니다. 결과 오브젝트는이 인수와 사용자가 제공 한 모든 인수를 사용하여 원래 호출 가능 함수를 호출하는 호출 가능 함수입니다. 의도 된 값으로 잠긴 상태로 유지하기 위해 여기에서 사용할 수 있습니다.
더 많은 설명이 필요합니까? 링크 된 질문에 대한 대답을 통해 차이점을 매우 간결하게 설명합니다. – BrenBarn
사실, 인수 값을 코딩 스타일에 따라 업데이트 할 수있는 이유는 무엇인지 이해하고 싶습니다. – Plouff