> 백엔드 개발 > 파이썬 튜토리얼 > Python의 클로저에 대해 이야기하기 - 클로저

Python의 클로저에 대해 이야기하기 - 클로저

高洛峰
풀어 주다: 2016-11-01 11:27:09
원래의
957명이 탐색했습니다.

파이썬에서의 클로저(Closure)는 단번에 이해될 수 있는 개념이 아니지만, 배우면 배울수록 그런 것은 어떻게든 이해해야 합니다.

클로저의 개념

클로저를 개념적으로 이해해 보겠습니다.

일부 언어에서는 함수 내에 다른 함수를 정의(중첩)할 수 있는 경우 내부 함수가 외부 함수의 변수를 참조하면 클로저가 발생할 수 있습니다. 클로저는 함수와 "비공개" 변수 세트 사이의 연관을 생성하는 데 사용될 수 있습니다. 이러한 개인 변수는 특정 함수에 대한 여러 호출에서 지속성을 유지합니다.

- 위키피디아)

쉽게 말하면, 함수가 객체로 반환되면 외부 변수가 연행되어 클로저를 형성합니다. 예시를 참조하세요.

def make_printer(msg): 
    def printer(): 
        print msg  # 夹带私货(外部变量) 
    return printer  # 返回的是函数,带私货的函数 
 
printer = make_printer('Foo!') 
printer()
로그인 후 복사

함수를 객체로 사용하는 것을 지원하는 프로그래밍 언어는 일반적으로 클로저를 지원합니다. Python, JavaScript 등이 있습니다.

클로저를 이해하는 방법

클로저의 의미는 무엇인가요? 클로저는 왜 필요한가요?

개인적으로 클로저의 의미는 외부 변수를 동반한다는 점이라고 생각합니다(Private 물품), 개인 물품을 포함하지 않는 경우 일반 기능과 차이가 없습니다. 동일한 기능이 다른 기능을 달성하기 위해 다른 사유재를 운반합니다. 실제로 클로저의 개념은 인터페이스 지향 프로그래밍의 개념과 매우 유사합니다. 클로저를 경량 인터페이스 캡슐화로 이해할 수도 있습니다.

인터페이스는 메소드 서명에 대한 제약 규칙 세트를 정의합니다.

def tag(tag_name): 
    def add_tag(content): 
        return "<{0}>{1}</{0}>".format(tag_name, content) 
    return add_tag 
 
content = &#39;Hello&#39; 
 
add_tag = tag(&#39;a&#39;) 
print add_tag(content) 
# <a>Hello</a> 
 
add_tag = tag(&#39;b&#39;) 
print add_tag(content) 
# <b>Hello</b>
로그인 후 복사

이 예에서는 콘텐츠에 태그를 추가하는 함수가 필요하지만, 특정 tag_name은 실제 필요에 따라 결정되며, 이는 add_tag(content)입니다. . 인터페이스 지향 방식으로 구현한다면 먼저 인터페이스로 add_tag를 작성하고 해당 매개변수와 반환 유형을 지정한 다음 각각 a와 b의 add_tag를 구현합니다.

그런데 클로저 개념에서 add_tag는 함수인데 tag_name과 content 두 개의 매개변수가 필요한데 tag_name 매개변수를 패키징하여 빼낸 것입니다. 그래서 처음에 포장하는 방법과 가져가는 방법을 알려주시면 됩니다.

위의 예는 사실 그다지 생생하지 않습니다. 사실 폐쇄라는 개념은 우리 삶과 일에서도 매우 흔합니다. 예를 들어, 휴대폰으로 전화를 걸 때 누구에게 전화를 걸지만 관심이 있을 뿐, 각 휴대폰 브랜드가 이를 어떻게 구현하고 어떤 모듈이 사용되는지는 걱정하지 않습니다. 또 다른 예는 레스토랑에 가서 식사를 할 때 그 서비스를 즐기기 위해서만 비용을 지불하면 됩니다. 그 식사에 배수구 기름이 얼마나 사용되었는지 알 수 없습니다. 이는 일부 기능이나 서비스(전화 걸기, 식사)를 반환하는 클로저로 간주될 수 있지만 이러한 기능은 외부 변수(안테나, 폐유 등)를 사용합니다.

클래스 인스턴스를 클로저로 생각할 수도 있습니다. 이 클래스를 구성할 때 이러한 매개변수는 클로저의 패키지입니다. 그러나 클래스는 클로저보다 훨씬 더 큽니다. 클로저는 단지 실행될 수 있는 함수이지만 클래스 인스턴스는 많은 메서드를 제공할 수 있기 때문입니다.

클로저를 사용해야 하는 경우

사실 파이썬에서는 클로저가 매우 흔하지만 이것이 클로저라는 사실에 특별히 주의를 기울이지 않았을 뿐입니다. 예를 들어, Python의 데코레이터에서 매개변수가 있는 데코레이터를 작성해야 하는 경우 일반적으로 클로저가 생성됩니다.

왜 Python의 데코레이터는 고정된 함수 인터페이스 형식이기 때문인가요? 데코레이터 함수(또는 데코레이터 클래스)가 함수를 수락하고 함수를 반환해야 합니다.

# how to define 
def wrapper(func1):  # 接受一个callable对象 
    return func2  # 返回一个对象,一般为函数 
     
# how to use 
def target_func(args): # 目标函数 
    pass 
 
# 调用方式一,直接包裹 
result = wrapper(target_func)(args) 
 
# 调用方式二,使用@语法,等同于方式一 
@wrapper 
def target_func(args): 
    pass 
 
result = target_func()
로그인 후 복사

그래서 데코레이터가 매개변수를 사용하면 이를 원래 데코레이터에 추가해야 할까요? 이러한 매개변수를 수신하기 위해 프로세서에 래핑된 레이어입니다. 이러한 매개변수(개인 상품)가 내부 데코레이터에 전달된 후 클로저가 형성됩니다. 따라서 데코레이터에 맞춤 매개변수가 필요한 경우 일반적으로 클로저가 형성됩니다. (클래스 데코레이터의 경우 예외)

def html_tags(tag_name): 
    def wrapper_(func): 
        def wrapper(*args, **kwargs): 
            content = func(*args, **kwargs) 
            return "<{tag}>{content}</{tag}>".format(tag=tag_name, content=content) 
        return wrapper 
    return wrapper_ 
 
@html_tags(&#39;b&#39;) 
def hello(name=&#39;Toby&#39;): 
    return &#39;Hello {}!&#39;.format(name) 
 
# 不用@的写法如下 
# hello = html_tag(&#39;b&#39;)(hello) 
# html_tag(&#39;b&#39;) 是一个闭包,它接受一个函数,并返回一个函数 
 
print hello()  # <b>Hello Toby!</b> 
print hello(&#39;world&#39;)  # <b>Hello world!</b>
로그인 후 복사

데코레이터에 대한 보다 심층적인 분석을 보려면 제가 작성한 다른 블로그를 읽어보세요.

더 깊게

사실 너무 깊게 들어갈 필요는 없습니다. 위의 개념을 이해하면 머리아플 것 같은 많은 코드가 바로 그것입니다.

클로저 패키지가 어떤 모습인지 살펴보겠습니다. 실제로 클로저 함수에는 모든 셀 객체를 저장하는 튜플을 정의하는 일반 함수에 비해 추가 __closure__ 속성이 있습니다. 각 셀 객체는 클로저에 모든 외부 변수를 하나씩 저장합니다.

>>> def make_printer(msg1, msg2): 
    def printer(): 
        print msg1, msg2 
    return printer 
>>> printer = make_printer(&#39;Foo&#39;, &#39;Bar&#39;)  # 形成闭包 
 
>>> printer.__closure__   # 返回cell元组 
(<cell at 0x03A10930: str object at 0x039DA218>, <cell at 0x03A10910: str object at 0x039DA488>) 
 
>>> printer.__closure__[0].cell_contents  # 第一个外部变量 
&#39;Foo&#39; 
>>> printer.__closure__[1].cell_contents  # 第二个外部变量 
&#39;Bar&#39;
로그인 후 복사

원리는 이렇게 간단합니다.

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿