2010-04-28 4 views
6

자동화 된 빌드를위한 기본 테스트 프레임 워크를 작성했습니다. 아래 코드는 서로 다른 프로그램을 사용하는 두 컴퓨터 간의 간단한 통신 테스트를 나타냅니다. 실제로 테스트를 수행하기 전에 완전히 정의하고 싶습니다. 따라서이 테스트는 모든 테스트가 선언 될 때까지 실제로 실행되지 않습니다. 이 코드는 단순히 테스트 선언입니다.Python Lambdas 및 변수 바인딩

remoteTests = [] 
for client in clients: 
    t = Test(
     name = 'Test ' + str(host) + ' => ' + str(client), 
     cmds = [ 
      host.start(CMD1), 
      client.start(CMD2), 

      host.wait(5), 

      host.stop(CMD1), 
      client.stop(CMD2), 
     ], 
     passIf = lambda : client.returncode(CMD2) == 0 
    ) 
remoteTests.append(t) 

아무튼 테스트를 실행 한 후 'passIf'에 정의 된 기능을 실행합니다. 이 테스트를 여러 클라이언트에 대해 실행하고 싶으므로 각 테스트를 반복하고 테스트를 정의합니다. 큰 문제는 아닙니다. 그러나 첫 번째 클라이언트에서 테스트를 실행 한 후 'passIf'는 람다 선언시 클라이언트가 아니라 클라이언트 목록의 마지막 클라이언트에서 평가됩니다.

내 질문 : 그렇다면 파이썬은 언제 lambdas에서 변수 참조를 바인드합니까? 나는 람다 외부에서 변수를 사용하는 것이 합법적이지 않다면 해석자는 내가 무슨 말을하고 있는지 전혀 알지 못할 것입니다. 대신, 그것은 마지막으로 '클라이언트'의 인스턴스에 자동으로 바인딩됩니다.

또한 의도 한대로 해상도를 강제 적용 할 수있는 방법이 있습니까?

답변

7

변수가 외부 범위에 정의되어 있으므로 lambda이 실행될 때 항상 목록의 마지막 클라이언트로 설정됩니다.

가 의도 한 결과를 얻으려면, 당신은 기본 값으로 람다에게 인수를 제공 할 수 있습니다 : 기본 값은 람다가 정의 된 시간에 평가

passIf = lambda client=client: client.returncode(CMD2) == 0 

때문에, 그 값이 올바른 유지됩니다.

다른 방법은 함수 내 람다를 생성하는 것이다 : 여기서

def createLambda(client): 
    return lambda: client.returncode(CMD2) == 0 
#... 
passIf = createLambda(client) 

람다 올바른 값을 갖는 createLambda 함수에 client 변수를 의미한다.

+0

기본값을 사용하면 완벽하게 작동합니다. 감사! – stringer

5

귀하의 passIf 인수 인 λ는 변수client의 범위를 나타냅니다. 변수 client이 만들어 질 때 객체가 참조하는 것이 아니라 변수 자체를 참조합니다. 루프가 끝난 후 이들을 passIf이라고하면 루프의 마지막 값을 참조합니다. (폐쇄 용어로, 파이썬의 폐쇄는 후기 바인딩하지 있습니다 초기 바인딩합니다.)

다행히이 초기 결합 폐쇄에 늦은 바인딩 폐쇄를 만들기 위해 매우 간단합니다. 이 인수로 호출되는 경우 일을하는 기능을 의미 하는가

passIf = lambda client=client: client.returncode(CMD2) == 0 

가 추가 인수를 가져오고 힘 엉망 : 당신은 당신이 바인딩 할 단순히 값을 기본으로하여 람다에게 인수를 제공함으로써 그것을 할 수 있습니다 우연히 - 또는 함수가 임의의 인수를 취할 때. 그래서 다른 방법은 다음과 같이하는 것입니다.

# Before your loop: 
def make_passIf(client): 
    return lambda: client.returncode(CMD2) == 0 

# In the loop 
t = Test(
    ... 
    passIf = make_passIf(client) 
) 
+0

멋진 설명. 나는 이것이 그것을 조금 더 분명하게한다라고 느낀다. "변수 클라이언트가 만들어 질 때 참조하는 개체가 아니라 변수 자체를 참조합니다." ** 변수 클라이언트는 변경 가능하기 때문에 루프의 마지막에는 마지막 '클라이언트'객체를 가리키고 있습니다. 따라서 그 가치는 지속됩니다. ** – narayan