[python] 클로저를 설명 할 수 있습니까 (파이썬과 관련이 있기 때문에)?

나는 폐쇄에 대해 많이 읽고 이해한다고 생각하지만 나 자신과 다른 사람들을 위해 그림을 흐리게하지 않고 누군가가 폐쇄를 가능한 한 간결하고 명확하게 설명 할 수 있기를 바랍니다. 나는 어디서 그리고 왜 사용하고 싶은지 이해하는 데 도움이 될 간단한 설명을 찾고 있습니다.



답변

폐쇄에 대한 폐쇄

객체는 메서드가 연결된 데이터이고 클로저는 데이터가 연결된 함수입니다.

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

부분 함수 예제에 맞지 않는 더 복잡한 클로저도 있습니다. 시간이 허락하는 한 더 자세히 설명하겠습니다.