클로저
파이썬에서는 함수도 객체입니다. 따라서 함수를 정의할 때 다른 중첩 함수를 정의하고 중첩 함수를 반환할 수 있습니다. 예:
from math import pow def make_pow(n): def inner_func(x): # 嵌套定义了 inner_func return pow(x, n) # 注意这里引用了外部函数的 n return inner_func # 返回 inner_func
위 코드에서 make_pow 함수는 내부 함수 inner_func를 정의한 다음 이 함수를 반환합니다. 따라서 make_pow를 사용하여 다른 함수를 생성할 수 있습니다:
>> > pow2 = make_pow(2) # pow2 是一个函数,参数 2 是一个自由变量 >> > pow2 <function inner_func at 0x10271faa0 > >> > pow2(6) 36.0
또한 내부 함수 inner_func가 외부 함수 make_pow의 자유 변수 n을 참조한다는 사실도 알아냈습니다. 이는 make_pow 함수의 수명 주기가 끝나면 다음을 의미합니다. 이후에도 변수 n은 inner_func에 의해 참조되는 inner_func에 계속 저장됩니다.
>> > del make_pow # 删除 make_pow >> > pow3 = make_pow(3) Traceback(most recent call last): File "<stdin>", line 1, in < module > NameError: name 'make_pow' is not defined >> > pow2(9) # pow2 仍可正常调用,自由变量 2 仍保存在 pow2 中 81.0
---|---
위의 상황과 마찬가지로 함수는 외부 함수의 관련 매개변수와 변수를 참조하는 내부 함수를 반환합니다. 내부 함수를 클로저라고 합니다.
위의 예에서 inner_func는 자유 변수 n을 참조하는 클로저입니다.
클로저의 역할
클로저의 가장 큰 특징은 클로저를 생성한 환경이 해제되어도 클로저가 여전히 존재한다는 점입니다. ;
전달된 매개변수가 동일하더라도 클로저는 런타임에 여러 인스턴스를 가질 수 있습니다. 예:
>> > pow_a = make_pow(2) >> > pow_b = make_pow(2) >> > pow_a == pow_b False
클로저 패키지를 사용하면 클래스 인스턴스를 모의할 수도 있습니다.
여기서 클래스를 구성하여 한 지점에서 다른 지점까지의 거리를 알아보세요:
from math import sqrt class Point(object): def __init__(self, x, y): self.x, self.y = x, y def get_distance(self, u, v): distance = sqrt((self.x - u) ** 2 + (self.y - v) ** 2) return distance >> > pt = Point(7, 2) # 创建一个点 >> > pt.get_distance(10, 6) # 求到另一个点的距离 5.0
클로저를 사용하여 구현:
def point(x, y): def get_distance(u, v): return sqrt((x - u) ** 2 + (y - v) ** 2) return get_distance >> > pt = point(7, 2) >> > pt(10, 6) 5.0
보시다시피 결과는 동일하지만 클래스를 사용하는 것보다 클로저를 사용하는 것이 더 간결합니다.
일반적인 오해
클로저의 개념은 매우 간단하지만 구현 시 다음 예와 같이 오해가 발생하기 쉽습니다.
def count(): funcs = [] for i in [1, 2, 3]: def f(): return i funcs.append(f) return funcs
이 예에서는 for 루프에서 함수가 생성되고 funcs에 저장됩니다. 이제 위 함수를 호출하면 반환 결과가 1, 2, 3이라고 생각할 수 있지만 실제로는 그렇지 않습니다.
>> > f1, f2, f3 = count() >> > f1() 3 >> > f2() 3 >> > f3() 3
왜요? 그 이유는 위의 함수 f가 변수 i를 참조하지만 함수 f가 즉시 실행되지 않기 때문입니다. for 루프가 끝나면 변수 i의 값은 3이고, funcs의 함수가 참조하는 변수는 모두 3입니다. , 최종 결과는 모두 3입니다.
따라서 클로저에서 루프 변수나 나중에 변경되는 변수를 참조하지 않도록 노력해야 합니다.
위 상황을 어떻게 해결하나요? 다음과 같이 다른 함수를 만들고 루프 변수의 값을 함수에 전달할 수 있습니다.
def count(): funcs = [] for i in [1, 2, 3]: def g(param): f = lambda: param # 这里创建了一个匿名函数 return f funcs.append(g(i)) # 将循环变量的值传给 g return funcs >> > f1, f2, f3 = count() >> > f1() 1 >> > f2() 2 >> > f3() 3
요약
클로저는 자유 변수를 전달하는 함수입니다. 클로저를 생성한 외부 함수의 수명 주기가 종료되더라도 클로저가 참조하는 자유 변수는 여전히 존재합니다.
클로저에는 여러 인스턴스가 실행될 수 있습니다.
클로저의 루프 변수나 나중에 변경될 변수를 참조하지 마세요.
위는 Python Advanced: closure carry state의 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!