2017-11-08 1 views
0

나는 람다를 파이썬으로 배우고있다. 각 함수 fi(x)이 목록 x을 취하고 (x[i]-1)을 반환하도록 함수 f = [f1, f2...]의 목록을 만들어야합니다.왜이 간단한 람다 함수가 기괴한 결과를 내고 있습니까?

이것은 코딩을 시도한 방법이지만 놀라운 결과를 얻고 있습니다. 왜 세 장의 인쇄본이 각각 다른 결과를 내는지 이해해주십시오. 마지막 두 사람은 절대로 엉망이되었습니다.

f = [(lambda x: x[i]-1) for i in range(5)] 
# I expect f to be [ (lambda x: x[0]-1), (lambda x: x[1]-1), ...] 

x = [1, 2, 3, 4, 5] 

print f[0](x), f[1](x), f[2](x) # output: 4 4 4 !! 
print [f[i](x) for i in range(5)] # output: [0, 1, 2, 3, 4] as expected 
print [f[k](x) for k in range(5)] # output: [4, 4, 4, 4, 4] wha?!!! 

편집 :이 질문은 suggested duplicate과 완전히 다릅니다. 링크 된 질문에서 사용자가 함수 호출 대신 함수 목록을 만든 간단한 오류가있었습니다. 그러나 Tomasz Gandor의 대답은 여러 가지 예제를 사용하여 여기에서 질문 한 것과 동일한 문제에 대해 설명합니다.

+0

https://stackoverflow.com/questions/6076270/python-lambda-function-in-list-comprehensions – 101

+0

그냥 호기심에서, 왜 당신이 뭔가 코딩하고 있습니다 .. 기묘한? 순수한 학문적 관심사? 결국 Guido는 구현 한 것을 후회합니다. http://legacy.python.org/doc/essays/ppt/regrets/PythonRegrets.pdf – Arne

+0

잘 파이썬 3에서는'i'와 함께 작동하지 않습니다 ... – Szabolcs

답변

5

그건 일반적인 잡았다. 당신이 찾고있는

f = [(lambda x, i=i: x[i]-1) for i in range(5)] 
z = [1,2,3,4,5] 
print f[0](z),f[1](z),f[2](z) 
0 1 2 

귀하의 목록에 이해가 i 5 개 기능, 모든 점을 생성합니다. 루프의 끝에서, i는 4. 따라서 상관없이 부르는 람다, 그것은 당신은 람다 함수의 로컬 변수에, 난의 현재 값을 할당 하려는 i

4로 evalutes 없습니다 같습니다. 선택적 인수을 사용하면됩니다.

런타임시 Lambda evalutes params. 파이썬은, 그것을 좀 더 빛을 흘릴 수있는이 같은 뭔가를 정의 할 수 있습니다 :

>>> f = lambda x: x[i] - 1 
>>> l = [1, 2, 3, 4] 
>>> f(l) 

Traceback (most recent call last): 
    File "<pyshell#91>", line 1, in <module> 
    f(l) 
    File "<pyshell#89>", line 1, in <lambda> 
    f = lambda x: x[i] - 1 
IndexError: list index out of range 

업데이트를 : 의견의 질문에 회신이 예는 원래의 질문에 덜 관련이 있지만 도움 더 나은 당신이 woul, 당신은 f을 선언하기 전에 myvar를 선언하지 않으면 기능 PARAMS 평가가

myvar=1 

def f(myvar=myvar): 
    print myvar 

f() # prints 1 
f(2) # prints 2 
myvar = 5 
f() # prints 1 

을 발생하는 방법을 이해하는 d는 NameError: name 'myvar' is not defined입니다. 이것은 함수 변수가 '컴파일'시간에 평가 되었기 때문입니다. Lambda의 에 대한 평가는이지만 옵션 인수를 제공 할 때 즉시 발생합니다 (따라서 i = i). 그것은 주제에 대한 더 많은 명확성을 제공하기를 바랍니다 :

+0

매개 변수의 값과 동일한 이름을 지정하지 않으려면 다른 이름으로 인덱스를 정의하는 것이 더 낫지 않습니까? 예 : 범위 = (5)의 i에 대해 f = [(λ x, idx = i : x [idx] -1)] – Arne

+0

파이썬의 범위 지정 규칙은 나에게 직관적이지 않습니다 (C/C++ 배경에서옵니다). 필자의 예에서 나는 i의 범위가 첫 번째 줄로 제한되어 있다고 가정했다. –

+0

@ArneRecknagel 람다 정의 외에도 코드에서 더 이상 다루지 않으므로 선택의 문제입니다. 두 옵션 모두 충분히 명확합니다. – Vinny

3

변수 i은 전역 범위에 있으며 함수를 호출 할 때 여전히 4입니다. 당신이 i = 1을 할 경우, 당신이 개 비정상적인 출력은

1 1 1[1 1 1 1 1] 내가이 작품을 발견하게됩니다

i
g = lambda i: lambda x: x[i] - 1 
f = [ g(i) for i in range(5) ] # i missed here 
print [f[k]([1,2,3,4,5]) for k in range(5)] # [0, 1, 2, 3, 4] 

이제 두 번째 람다에 속합니다.

관련 문제