2017-10-03 5 views
1

일부 데이터를 미리 불러오고 싶은 튜플이 있습니다. 현재 내가하고있는 방식은 다음과 같습니다. 본질적으로, 나는 새로운 함수의 목록을 만들고, 한 번에 하나씩 람다 함수를 추가 한 다음 튜플로 재 변환한다. 그러나 코드의 다른 부분에서 이러한 함수를 사용하면 모든 함수가 코드의 마지막 코드 인 것처럼 작동합니다. 여기 파이썬에서 람다 함수 목록 초기화하기

def newfuncs(data, funcs): 
    newfuncs = [] 
    for f in funcs: 
     newf = lambda x: f(x, data) 
     newfuncs.append(newf) 
    return tuple(newfuncs) 

문제

funcs = (lambda x, y: x + y, lambda a, b: a - b) 
funcs = newfuncs(10, funcs) 
print(funcs[0](5)) 
print(funcs[1](5)) 

간단한 예이고 I는 숫자 (15)는 그 후, 인쇄 기대 -5. 그러나이 코드는 숫자 -5를 두 번 인쇄합니다. 왜 이런 일이 일어나는 지 이해할 수 있다면 누구나 이해할 수있을 것입니다. 감사!

답변

3

, 문제는 모든lambda 함수, 루프의 끝에 있도록 모든lambda가 동일한 f보고 에 할당 된 동일한 변수 변수 f로한다.

여기 솔루션 중 하나 functools.partial를 사용하거나 lambda의 범위가 기본 인수를 작성하는 것입니다 : 지금 제공하기 전에 이러한 lambda의 호출

def newfuncs(data, funcs): 
    newfuncs = [] 
    for f in funcs: 
     newf = lambda x, f=f: f(x, data) # note the f=f bit here 
     newfuncs.append(newf) 
    return tuple(newfuncs) 

을 :

15 
-5 

당신이 만약 ' python3.x를 사용하는 경우 범위가 지정된 기본 arg 접근에 대한 가능한 안전 기능으로 this comment by ShadowRanger을 살펴보십시오.

+1

사이드 노트 : 파이썬 3을 사용하고 있으며 범위가 지정된 기본 인수 방식을 사용하는 경우 이러한 인수를 키워드 전용으로 설정하는 것이 좋습니다. 따라서 실수로 추가 위치 매개 변수를 전달해도 자동으로 경계를 덮어 쓰지는 않습니다 값 (이 경우에는'f'라는 이름을 명시 적으로 키워드 인수로 전달함으로써 만 변경할 수 있습니다). 차이점은'lambda x, f = f :'를'lambda x, *, f = f :'로 변경하는 것인데,'*'(이름 없음)은 모든 인수를 키워드 전용으로 만든다. – ShadowRanger

+0

@ShadowRanger 아주 좋았어, 고마워. –

2

이것은 잘 알려진 Python "문제"입니다. 또는 "이것이 파이썬이되는 방식입니다."

당신은 튜플 생성 :

(x => f(x, data), x => f(x, data)) 

을하지만 f 무엇인가? f은 마지막으로 함수를 호출 할 때까지 평가되지 않습니다!

우선, f(x, y)=>x+y이었다. 그런 다음 for -loop에서 f(x, y)=>x-y으로 재 할당했습니다.

마지막으로 함수를 호출 할 때 f의 값이 조회됩니다. 이 시점에서 f의 값은 무엇입니까? 이 값은 모든 기능에 대해 (x, y)=>x-y입니다. 모든 함수는 뺄셈을합니다. 이는 f이 재 할당되기 때문입니다. 단 하나의 f 만 있습니다. 그리고 그 중 하나의 값만이 f은 람다가 호출되기 전에 빼기 함수로 설정됩니다. 아무도 관심이 경우

부칙

는, 다른 언어는 다른 방법으로이 문제를 접근. JavaScript는 다소 흥미 롭습니다 (일부는 혼란 스러울 것입니다). 왜냐하면 OP가 예기치 않은 Python 방식과 OP가 기대했던 다른 방식을 사용하기 때문입니다. 자바 스크립트에서 : 당신이 letvar에 변경하면

그러나
> let funcs = [] 
> for (let f of [(x,y)=>x+y, (x,y)=>x-y]) { 
    funcs.push(x=>f(x,10)); 
    } 
> funcs[0](5) 
15 
funcs[1](5) 
-5 

, 파이썬처럼 행동하고 얻을 -5 모두! let을 사용하면 for 루프의 각 반복마다 f이 달라집니다. var으로 전체 기능은 동일한 f을 공유하며 계속 재 할당됩니다. 이것이 파이썬이 작동하는 방식입니다.

cᴏʟᴅsᴘᴇᴇᴅ는 각 반복에 대해 f이 다르다는 것을 확인하는 방법을 보여주었습니다. Python에서는이를 깔끔하게 처리 할 수 ​​있으며, 람다의 두 번째 인수는 f 해당 반복에 로컬. 그것은 매우 시원합니다. 그래서 당신의 도움이된다면 그들의 대답을 받아 들여야합니다.언급 한 바와 같이

+0

자바 스크립트 샘플을 추가해 주셔서 감사합니다. –