파이썬 장식기는 왜 이해하기 어려워요?

3907 단어
프로젝트든 면접이든 장식기 화제와 떨어질 수 없다. 장식기의 강력함은 기존의 업무 논리를 수정하지 않은 상황에서 코드를 확장할 수 있다는 데 있다. 권한 검사, 사용자 인증, 로그 기록, 성능 테스트, 사무 처리, 캐시 등은 장식기의 절호의 응용 장면으로 코드를 최대한 복용할 수 있다.
그러나 왜 초보자가 장식기에 대한 이해가 이렇게 어려운지, 나는 본질적으로 파이톤 함수에 대한 이해가 제대로 되지 않는다고 생각한다. 왜냐하면 장식기는 본질적으로 함수이기 때문이다.

함수 정의


장식기를 이해하기 전에 함수의 작업 원리를 이해해야 한다. 우리는 가장 간단한 함수 정의부터 시작한다.
def foo(num):
    return num + 1

위에서 하나의 함수를 정의했는데 이름은 foo이고 foo도 변수 이름으로 이해할 수 있다. 이 변수는 하나의 함수 대상을 가리킨다
호출 함수는 함수 이름에 괄호를 붙이고 필요한 매개 변수를 전달하기만 하면 된다. (함수가 정의할 때 매개 변수가 있다면)
value = foo(3)
print(value) # 4

변수 이름 foo 은 현재 함수 대상을 가리키지만, 다른 함수도 가리킬 수 있다.
def bar():
    print("bar")
foo = bar
foo() # bar

함수를 반환값으로 삼다


Python에서는 모든 것이 객체이고 함수도 예외가 아닙니다. 함수는 정수처럼 다른 함수의 반환값으로 사용할 수 있습니다. 예를 들어 다음과 같습니다.
def foo():
    return 1

def bar():
    return foo

print(bar()) # 

print(bar()()) # 1 
#    
print(foo()) # 1

호출 함수bar()의 반환값은 함수 대상이다. 반환값은 함수이기 때문에 우리는 반환값을 계속 호출할 수 있다. (기억해라. 호출 함수는 함수 이름 뒤에 () 호출bar()()은 호출foo()에 해당한다. 변수foo가 가리키는 대상과bar()의 반환값은 같은 대상이기 때문이다.

함수를 매개 변수로 삼다


함수는 정수와 같이 함수의 매개 변수로 사용할 수도 있다. 예를 들어 다음과 같다.
def foo(num):
    return num + 1

def bar(fun):
    return fun(3)

value = bar(foo)
print(value)  # 4

함수bar는 하나의 매개 변수를 수신한다. 이 매개 변수는 호출할 수 있는 함수 대상으로 함수foobar에 전달할 때foo와fun 두 변수의 이름이 같은 함수 대상을 가리키기 때문에fun(3)을 호출하는 것은foo(3)를 호출하는 것과 같다.

함수 중첩


함수는 매개변수 및 반환값뿐만 아니라 다음과 같은 네스트된 함수로 다른 함수에도 정의할 수 있습니다.
def outer():
    x = 1
    def inner():
        print(x)
    inner()

outer() # 1
inner 중첩 함수로 외부 함수의 변수에 접근할 수 있으며 outer 함수를 호출할 때 세 가지 일이 발생했다.
  • 변수x에 1
  • 을 부여한다.
  • 플러그인 함수inner를 정의합니다. 이 함수는 3단계
  • 까지 호출되지 않았기 때문에 inner의 코드를 실행하지 않습니다.
  • inner 함수를 호출하여 inner의 코드 논리를 실행합니다.

  • 가방을 닫다


    다시 한 번 예를 살펴보자.
    def outer(x):
        def inner():
            print(x)
    
        return inner
    closure = outer(1)
    closure() # 1

    마찬가지로 플러그인 함수입니다. 조금만 바꾸면 국부 변수 x를 매개 변수로 전달합니다. 플러그인 함수는 함수에서 직접 호출되지 않고 되돌아오는 값으로 되돌아옵니다. 여기의closure는 패키지입니다. 본질적으로 패키지는 함수입니다. 패키지는 자유 변수(x)의 함수(inner)를 인용한 함수입니다.

    장식기


    계속해서 아래를 내려다보다.
    def foo():
        print("foo")

    위의 이 함수는 아마도 역사상 가장 간단한 업무 코드일 것이다. 비록 쓸모가 없지만 문제를 설명할 수 있으면 된다.이 함수를 실행할 때 로그를 추가해야 하는 새로운 요구 사항이 있습니다.
    def foo():
        print("      ")
        print("foo")
        print("      ")

    기능이 실현되는 유일한 문제는 그것이 원래의 코드에 침입하여 로그 논리를 추가해야 한다는 것이다. 만약에 이런 함수가 수십 개 더 있다면 로그를 추가해야 한다. 분명히 이런 코드는 조금도 파이토닉이 아니다.그렇다면 업무 코드를 수정하지 않는 앞당겨 로그 기능을 실현할 수 있을까?정답은 장식기다.
    def outer(func):
        def inner():
            print("      ")
            func() #     
            print("      ")
        return inner
    
    def foo():
        print("foo")
    
    foo = outer(foo) 
    foo()

    나는 foo 함수 안의 어떤 논리도 수정하지 않았고, 단지foo 변수에 다시 값을 부여하여 새로운 함수 대상을 가리켰다.마지막으로 foo () 를 호출하면 로그를 출력할 수 있을 뿐만 아니라 업무 논리도 실행됩니다.이제 그것의 집행 절차를 분석해 봅시다.
    여기의 outer 함수는 사실 하나의 장식기이다. 장식기는 함수를 매개 변수로 하고 새로운 함수를 되돌려주는 클립이다. 본질적으로 장식기도 함수이다.outer 함수의 반환값은 inner 함수입니다. inner 함수에서 로그 조작을 실행하는 것 외에 업무 코드도 있습니다. 이 함수는foo 변수에 다시 값을 부여한 후foo()를 호출하면 inner()를 호출하는 것과 같습니다.
    foo 재할당 전:
    값을 재지정하면 foo = outer(foo)
    또한 파이썬은 함수의 정의에 사용되는 구문 설탕@을 장식기에 제공합니다.
    @outer
    def foo():
        print("foo")
    
    foo()

    이렇게 하면 수동으로 foo에 값을 다시 부여하는 절차를 줄일 수 있다.
    여기까지 장식기에 대해 이해가 됐나요?물론 장식기는 더욱 복잡할 수 있다. 예를 들어 파라미터를 받아들일 수 있는 장식기, 유형을 바탕으로 하는 장식기 등이다.다음 편은 장식기의 응용 장면을 쓸 수 있다.

    좋은 웹페이지 즐겨찾기