programing

중첩 함수의 지역 변수

nasanasas 2020. 8. 18. 07:46
반응형

중첩 함수의 지역 변수


좋아요, 이것에 대해 참아주세요. 끔찍하게 복잡해 보일 것이라는 것을 압니다.하지만 무슨 일이 일어나고 있는지 이해하도록 도와주세요.

from functools import partial

class Cage(object):
    def __init__(self, animal):
        self.animal = animal

def gotimes(do_the_petting):
    do_the_petting()

def get_petters():
    for animal in ['cow', 'dog', 'cat']:
        cage = Cage(animal)

        def pet_function():
            print "Mary pets the " + cage.animal + "."

        yield (animal, partial(gotimes, pet_function))

funs = list(get_petters())

for name, f in funs:
    print name + ":", 
    f()

제공 :

cow: Mary pets the cat.
dog: Mary pets the cat.
cat: Mary pets the cat.

그래서 기본적으로 왜 세 가지 다른 동물을 얻지 못합니까? cage중첩 함수의 로컬 범위에 '패키징' 되지 않습니까? 그렇지 않은 경우 중첩 함수에 대한 호출은 지역 변수를 어떻게 조회합니까?

이런 종류의 문제가 발생한다는 것은 일반적으로 '잘못하는 것'을 의미한다는 것을 알고 있지만 어떤 일이 발생하는지 이해하고 싶습니다.


중첩 함수는 정의 될 때가 아니라 실행될 때 상위 범위에서 변수를 찾습니다.

함수 본문이 컴파일되고 '자유'변수 (할당에 의해 함수 자체에 정의되지 않음)가 확인 된 다음 코드가 각 셀을 참조하는 인덱스를 사용하여 함수에 클로저 셀로 바인딩됩니다. pet_function따라서 하나의 자유 변수 ( cage)가 있으며,이 변수 는 클로저 셀, 인덱스 0을 통해 참조됩니다. 클로저 자체 cageget_petters함수 의 지역 변수 가리 킵니다 .

실제로 함수를 호출 할 때, 그 폐쇄는 다음의 값을보고하는 데 사용되는 cage주변 범위에서 함수를 호출 할 때 . 여기에 문제가 있습니다. 함수를 호출 할 때까지 get_petters함수는 이미 결과 계산을 완료했습니다. cage이 실행되는 동안 어떤 시점에서 로컬 변수가 각각 할당 된 'cow', 'dog'그리고 'cat'문자열을하지만 함수의 끝에서, cage마지막 값을 포함한다 'cat'. 따라서 동적으로 반환되는 각 함수를 호출하면 값이 'cat'인쇄됩니다.

해결 방법은 클로저에 의존하지 않는 것입니다. 당신은 사용할 수있는 일부 기능을 대신 만드는 새로운 기능 범위를 A와 변수를, 또는 바인드 키워드 매개 변수에 대한 디폴트 값 .

  • 다음을 사용하는 부분 함수 예제 functools.partial():

    from functools import partial
    
    def pet_function(cage=None):
        print "Mary pets the " + cage.animal + "."
    
    yield (animal, partial(gotimes, partial(pet_function, cage=cage)))
    
  • 새 범위 예제 만들기 :

    def scoped_cage(cage=None):
        def pet_function():
            print "Mary pets the " + cage.animal + "."
        return pet_function
    
    yield (animal, partial(gotimes, scoped_cage(cage)))
    
  • 변수를 키워드 매개 변수의 기본값으로 바인딩 :

    def pet_function(cage=cage):
        print "Mary pets the " + cage.animal + "."
    
    yield (animal, partial(gotimes, pet_function))
    

scoped_cage루프 에서 함수 를 정의 할 필요가 없습니다 . 컴파일은 루프의 각 반복이 아니라 한 번만 발생합니다.


내 이해는 산출 된 pet_function이 실제로 호출 될 때 부모 함수 네임 스페이스에서 케이지가 이전이 아니라 호출된다는 것입니다.

그래서 당신이 할 때

funs = list(get_petters())

마지막으로 생성 된 케이지를 찾는 3 개의 함수를 생성합니다.

마지막 루프를 다음으로 바꾸면 :

for name, f in get_petters():
    print name + ":", 
    f()

당신은 실제로 얻을 것입니다 :

cow: Mary pets the cow.
dog: Mary pets the dog.
cat: Mary pets the cat.

이것은 다음에서 비롯됩니다.

for i in range(2): 
    pass

print i is 1

after iterating the value of i is lazily stored as its final value.

As a generator the function would work (i.e. printing each value in turn), but when transforming to a list it runs over the generator, hence all calls to cage (cage.animal) return cats.

참고URL : https://stackoverflow.com/questions/12423614/local-variables-in-nested-functions

반응형