나는 폐쇄에 대해 많이 읽고 이해한다고 생각하지만 나 자신과 다른 사람들을 위해 그림을 흐리게하지 않고 누군가가 폐쇄를 가능한 한 간결하고 명확하게 설명 할 수 있기를 바랍니다. 나는 어디서 그리고 왜 사용하고 싶은지 이해하는 데 도움이 될 간단한 설명을 찾고 있습니다.
답변
객체는 메서드가 연결된 데이터이고 클로저는 데이터가 연결된 함수입니다.
def make_counter():
i = 0
def counter(): # counter() is a closure
nonlocal i
i += 1
return i
return counter
c1 = make_counter()
c2 = make_counter()
print (c1(), c1(), c2(), c2())
# -> 1 2 1 2
답변
간단합니다. 제어 흐름이 해당 범위를 떠난 후 잠재적으로 포함 범위에서 변수를 참조하는 함수입니다. 마지막 부분은 매우 유용합니다.
>>> def makeConstantAdder(x):
... constant = x
... def adder(y):
... return y + constant
... return adder
...
>>> f = makeConstantAdder(12)
>>> f(3)
15
>>> g = makeConstantAdder(4)
>>> g(3)
7
12와 4는 각각 f와 g 내부에서 “사라졌다”는 점에 유의하십시오.이 기능은 f와 g가 적절한 클로저를 만드는 이유입니다.
답변
이 거칠고 간결한 정의가 마음 에 듭니다 .
더 이상 활성화되지 않은 환경을 참조 할 수있는 기능입니다.
나는 추가 할 것이다
클로저를 사용하면 변수를 매개 변수로 전달하지 않고도 함수에 변수를 바인딩 할 수 있습니다 .
매개 변수를 허용하는 데코레이터는 클로저에 일반적으로 사용됩니다. 클로저는 이러한 종류의 “기능 팩토리”에 대한 일반적인 구현 메커니즘입니다. 나는 전략이 런타임에 데이터에 의해 수정 될 때 전략 패턴 에서 클로저를 자주 사용 합니다.
익명의 블록 정의를 허용하는 언어 (예 : Ruby, C #)에서 클로저를 사용하여 새로운 새로운 제어 구조를 구현할 수 있습니다. 익명 블록의 부족은 Python에서 클로저의 한계 중 하나 입니다.
답변
솔직히 말해서, “폐쇄”가 정확히 무엇인지, 그리고 그것에 대해 “폐쇄”가 무엇인지에 대해 명확하지 않은 것을 제외하고는 클로저를 완벽하게 이해합니다. 용어 선택의 논리를 찾는 것을 포기하는 것이 좋습니다.
어쨌든, 여기에 내 설명이 있습니다.
def foo():
x = 3
def bar():
print x
x = 5
return bar
bar = foo()
bar() # print 5
여기서 핵심 아이디어는 foo에서 반환 된 함수 객체가 ‘x’가 범위를 벗어 났고 없어야하지만 로컬 var ‘x’에 대한 후크를 유지한다는 것입니다. 이 후크는 var 자체에 대한 것이지 var가 당시에 가졌던 값이 아니므로 bar가 호출되면 3이 아닌 5를 인쇄합니다.
또한 Python 2.x에는 제한된 클로저가 있음을 분명히하십시오. ‘x = bla’를 작성하면 foo의 ‘x’에 할당되지 않고 bar에서 로컬 ‘x’를 선언하기 때문에 ‘bar’내부에서 ‘x’를 수정할 수있는 방법이 없습니다. . 이것은 Python의 assignment = declaration의 부작용입니다. 이 문제를 해결하기 위해 Python 3.0은 nonlocal 키워드를 도입했습니다.
def foo():
x = 3
def bar():
print x
def ack():
nonlocal x
x = 7
x = 5
return (bar, ack)
bar, ack = foo()
ack() # modify x of the call to foo
bar() # print 7
답변
나는 클로저가 무엇인지 설명하는 것과 같은 맥락에서 트랜잭션이 사용되는 것을 들어 본 적이 없으며 실제로 여기에는 트랜잭션 의미가 없습니다.
외부 변수 (상수)를 “닫기”때문에 클로저라고합니다. 즉, 단순한 함수가 아니라 함수가 생성 된 환경의 인클로저입니다.
다음 예제에서 x를 변경 한 후 클로저 g를 호출하면 g가 x에 대해 닫히기 때문에 g 내의 x 값도 변경됩니다.
x = 0
def f():
def g():
return x * 2
return g
closure = f()
print(closure()) # 0
x = 2
print(closure()) # 4
답변
다음은 클로저에 대한 일반적인 사용 사례입니다-GUI 요소에 대한 콜백 (버튼 클래스를 서브 클래 싱하는 대신). 예를 들어, 버튼 누름에 대한 응답으로 호출되는 함수를 생성하고 클릭 처리에 필요한 상위 범위의 관련 변수를 “닫기”할 수 있습니다. 이렇게하면 동일한 초기화 함수에서 매우 복잡한 인터페이스를 연결하여 모든 종속성을 클로저에 구축 할 수 있습니다.
답변
파이썬에서 클로저는 변수가 불변으로 바인딩 된 함수의 인스턴스입니다.
실제로 데이터 모델 은 함수의 __closure__
속성 에 대한 설명에서이를 설명 합니다.
함수의 자유 변수에 대한 바인딩을 포함 하는 셀 의 튜플 또는 없음 . 읽기 전용
이를 증명하려면 :
def enclosure(foo):
def closure(bar):
print(foo, bar)
return closure
closure_instance = enclosure('foo')
분명히 우리는 이제 변수 name에서 가리키는 함수가 있다는 것을 알고 closure_instance
있습니다. 표면 상으로는 객체를 사용하여 호출 bar
하면 문자열 'foo'
과 문자열 표현이 무엇이든 인쇄해야합니다 bar
.
사실, 문자열 ‘foo’ 는 함수의 인스턴스에 묶여 있으며, cell_contents
속성의 튜플에있는 첫 번째 (유일한) 셀 의 속성 에 액세스하여 여기서 직접 읽을 수 있습니다 __closure__
.
>>> closure_instance.__closure__[0].cell_contents
'foo'
별도로 셀 객체는 C API 문서에 설명되어 있습니다.
그리고 우리는 클로저의 사용법을 보여줄 수 있습니다 'foo'
. 함수에 갇혀 있고 변하지 않습니다.
>>> closure_instance('bar')
foo bar
>>> closure_instance('baz')
foo baz
>>> closure_instance('quux')
foo quux
그리고 아무것도 바꿀 수 없습니다.
>>> closure_instance.__closure__ = None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: readonly attribute
부분 기능
주어진 예제는 부분 함수로 클로저를 사용하지만 이것이 우리의 유일한 목표라면 동일한 목표를 다음과 같이 달성 할 수 있습니다. functools.partial
>>> from __future__ import print_function # use this if you're in Python 2.
>>> partial_function = functools.partial(print, 'foo')
>>> partial_function('bar')
foo bar
>>> partial_function('baz')
foo baz
>>> partial_function('quux')
foo quux
부분 함수 예제에 맞지 않는 더 복잡한 클로저도 있습니다. 시간이 허락하는 한 더 자세히 설명하겠습니다.