python - 점프투파이썬 - 파이썬 문자열 슬라이싱




파이썬과 관련하여 클로저를 설명 할 수 있습니까? (9)

나는 폐쇄에 대해 많은 것을 읽었으며 그것을 이해한다고 생각하지만, 나 자신과 다른 사람들을 위해 그림을 흐리게하지 않으면 서 누군가가 폐쇄를 가능한 한 간결하고 명확하게 설명 할 수 있기를 바랍니다. 위치와 이유를 이해하는 데 도움이되는 간단한 설명을 찾고 있습니다.


간단합니다. 제어 흐름이 해당 범위를 벗어난 후 포함 범위의 변수를 참조하는 함수입니다. 마지막 비트는 매우 유용합니다.

>>> 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 #)를 허용하는 언어에서는 클로저를 사용하여 새로운 제어 구조를 구현할 수 있습니다. 익명 블록의 부족은 파이썬에서 클로저의 한계 중 하나입니다.


다음은 클로저에 대한 일반적인 사용 사례입니다. GUI 요소에 대한 콜백입니다 (버튼 클래스를 서브 클래 싱하는 대신 사용할 수 있음). 예를 들어, 버튼 누름에 대한 응답으로 호출 할 함수를 구성하고 클릭 처리에 필요한 상위 범위의 관련 변수를 "닫습니다". 이런 식으로 동일한 초기화 함수에서 매우 복잡한 인터페이스를 연결하여 모든 종속성을 클로저에 구축 할 수 있습니다.


솔직히 말해서, 나는 "폐쇄"가 무엇인지, 그리고 "폐쇄"가 무엇인지 명확하지 않은 것을 제외하고는 폐쇄를 완벽하게 잘 알고 있습니다. 용어 선택의 배후에있는 논리를 찾아 보는 것이 좋습니다.

어쨌든, 여기 내 설명이 있습니다 :

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를 인쇄합니다.

또한 파이썬 2.x는 클로저가 제한되어 있음을 분명히하십시오 : 'x = bla'을 쓰면 foo의 'x'에 할당되지 않고 'x'를 로컬에 선언하므로 'bar'에서 'x'를 수정할 수있는 방법이 없습니다 . 이것은 파이썬의 할당 = 선언의 부작용입니다. 이 문제를 해결하기 위해 Python 3.0에는 비 로컬 키워드가 도입되었습니다.

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

저에게 "클로저"는 자신이 만들어진 환경을 기억할 수있는 기능입니다. 이 기능을 사용하면 클로저에서 변수 또는 메소드를 사용할 수 있습니다. 다른 방법으로는 더 이상 존재하지 않거나 범위로 인해 도달 할 수 없기 때문에 사용할 수 없습니다. 이 코드를 루비로 봅시다 :

def makefunction (x)
  def multiply (a,b)
    puts a*b
  end
  return lambda {|n| multiply(n,x)} # => returning a closure
end

func = makefunction(2) # => we capture the closure
func.call(6)    # => Result equal "12"  

"곱하기"방법과 "x"변수가 더 이상 존재하지 않는 경우에도 작동합니다. 모두 폐쇄 기능이 기억하기 때문에.


저의 예와 폐쇄에 대한 설명을 나누고 싶습니다. 파이썬 예제와 스택 상태를 보여주기 위해 두 개의 그림을 만들었습니다.

def maker(a, b, n):
    margin_top = 2
    padding = 4
    def message(msg):
        print('\n’ * margin_top, a * n, 
            '  * padding, msg, ' ‘ * padding, b * n)
    return message

f = maker('*', '#', 5)
g = maker('', '♥’, 3)
…
f('hello')
g(‘good bye!')

이 코드의 출력은 다음과 같습니다.

*****      hello      #####

      good bye!    ♥♥♥

다음은 스택과 함수 객체에 연결된 클로저를 보여주는 두 개의 그림입니다.

메이커에서 함수를 돌려주는 경우

함수가 나중에 호출 될 때

함수가 매개 변수 또는 비 로컬 변수를 통해 호출되면 코드에는 margin_top, 패딩 및 a, b, n과 같은 로컬 변수 바인딩이 필요합니다. 함수 코드가 작동하도록하려면 오래 전에 사라진 메이커 함수의 스택 프레임에 액세스 할 수 있어야합니다.이 메시지는 '메시지의 함수 객체와 함께 찾을 수있는 클로저에 백업됩니다.


클로저에 대해 내가 본 가장 좋은 설명은 메커니즘을 설명하는 것이 었습니다. 그것은 다음과 같이 갔다 :

각 노드에 자식이 하나만 있고 단일 리프 노드가 현재 실행중인 프로 시저의 컨텍스트 인 축퇴 트리로 프로그램 스택을 상상해보십시오.

이제 각 노드가 하나의 자식 만 가질 수 있다는 제약을 완화하십시오.

이렇게하면 로컬 컨텍스트를 버리지 않고 프로 시저에서 리턴 할 수있는 구문 ( '수율')을 가질 수 있습니다 (즉, 리턴 할 때 스택에서 팝업되지 않음). 다음에 프로 시저가 호출 될 때 호출은 이전 스택 (트리) 프레임을 선택하고 중단 된 위치에서 계속 실행합니다.


파이썬에서 클로저는 변수가 불변으로 묶인 함수의 인스턴스입니다.

실제로 데이터 모델 은 함수의 __closure__ 속성에 대한 설명에서이를 설명합니다.

함수의 자유 변수에 대한 바인딩을 포함 하는 셀 이 없거나 하나도 없습니다. 읽기 전용

이것을 증명하려면 :

def enclosure(foo):
    def closure(bar):
        print(foo, bar)
    return closure

closure_instance = enclosure('foo')

분명히, 우리는 변수 이름 closure_instance 에서 지적한 함수를 가지고 있음을 알고 있습니다. 표면 상으로 bar 객체로 호출하면 문자열 'foo'bar 의 문자열 표현이 무엇이든 인쇄해야합니다.

실제로 문자열 'foo' 함수의 인스턴스에 바인딩되어 있으며 cell_contents 속성의 튜플에서 첫 번째 (및 유일한) 셀의 cell_contents 속성에 액세스하여 여기에서 직접 읽을 수 있습니다.

>>> 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

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


# A Closure is a function object that remembers values in enclosing scopes even if they are not present in memory.

# Defining a closure

# This is an outer function.
def outer_function(message):
    # This is an inner nested function.
    def inner_function():
        print(message)
    return inner_function

# Now lets call the outer function and return value bound to name 'temp'
temp = outer_function("Hello")
# On calling temp, 'message' will be still be remembered although we had finished executing outer_function()
temp()
# Technique by which some data('message') that remembers values in enclosing scopes 
# even if they are not present in memory is called closures

# Output: Hello

클로저가 충족해야 할 기준은 다음과 같습니다.

  1. 중첩 된 함수가 있어야합니다.
  2. 중첩 함수는 둘러싸는 함수에 정의 된 값을 참조해야합니다.
  3. 둘러싸는 함수는 중첩 함수를 반환해야합니다.
# Example 2
def make_multiplier_of(n): # Outer function
    def multiplier(x): # Inner nested function
        return x * n
    return multiplier
# Multiplier of 3
times3 = make_multiplier_of(3)
# Multiplier of 5
times5 = make_multiplier_of(5)
print(times5(3)) # 15
print(times3(2)) #  6




closures