데코레이터는 Python에서 함수나 코드를 캡슐화하는 데 사용되는 도구입니다. 여기서 제가 논의하고 싶은 내용은 인터넷에서 배울 수 있는 많은 기사입니다. 여러 데코레이터. 시퀀스에 대한 신화.
여러 데코레이터와 관련된 대부분의 함수 호출 시퀀스는 다음 예와 같이 하향식임을 나타냅니다.
def decorator_a(func): print 'Get in decorator_a' def inner_a(*args, **kwargs): print 'Get in inner_a' return func(*args, **kwargs) return inner_a def decorator_b(func): print 'Get in decorator_b' def inner_b(*args, **kwargs): print 'Get in inner_b' return func(*args, **kwargs) return inner_b @decorator_b @decorator_a def f(x): print 'Get in f' return x * 2 f(1)
위 코드는 먼저 두 가지 함수: decotator_a, decotator_b 이 두 함수의 함수는 함수를 매개변수로 받은 다음 생성된 다른 함수를 반환하는 것입니다(텍스트가 코드보다 더 혼란스럽습니다). 마지막으로 정의된 함수 f는 위에서 정의한 decotator_a, decotator_b를 데코레이션 함수로 사용한다. 1을 매개변수로 하여 데코레이팅된 함수 f를 호출한 후 decotator_a, decotator_b의 순서는 어떻게 됩니까(여기서 함수 실행 순서를 나타내기 위해 print 출력을 사용하여 함수 실행 순서를 확인합니다).
아무 생각 없이 상향식 원칙으로 판단한다면, decorator_a를 먼저 실행한 다음 decorator_b를 실행한 다음 Get in decorator_a, Get in inner_a가 먼저 출력되고 그 다음 Get in decorator_b, Get in inner_b가 출력됩니다. 그러나 이것은 사실이 아니다.
실제 실행 결과는 다음과 같습니다.
Get in decorator_a Get in decorator_b Get in inner_b Get in inner_a Get in f
왜 inner_b가 먼저 실행되고 나중에 inner_a가 실행되나요? 위의 문제를 완전히 이해하려면 먼저 함수와 함수 호출이라는 두 가지 개념을 구별해야 합니다. 위의 예에서 f는 함수라고 하고, f(1)은 함수 호출이라고 합니다. 후자는 전자에 의해 전달된 매개변수를 평가한 결과입니다. Python에서는 함수도 객체이므로 f는 함수 객체를 나타내며 그 값은 함수 자체입니다. f(1)은 함수에 대한 호출이고 해당 값은 호출의 결과입니다. 여기서 정의하면 f(1) 값은 2입니다. 마찬가지로 위의 decorator_a 함수를 예로 들면 내부적으로 정의된 함수 개체 inner_a를 반환합니다. inner_a에서는 func 함수가 호출되고 func 호출 결과가 값으로 반환됩니다.
두 번째로 명확히 해야 할 질문은 데코레이터가 함수를 데코레이션할 때 정확히 어떤 일이 발생하는지입니다. 이제 다음과 같이 가정하여 예제를 단순화합니다.
def decorator_a(func): print 'Get in decorator_a' def inner_a(*args, **kwargs): print 'Get in inner_a' return func(*args, **kwargs) return inner_a @decorator_a def f(x): print 'Get in f' return x * 2
데코레이터를 소개하는 많은 기사에서 말했듯이:
@decorator_a def f(x): print 'Get in f' return x * 2 # 相当于 def f(x): print 'Get in f' return x * 2 f = decorator_a(f)
따라서 인터프리터가 이 코드를 실행할 때 decorator_a는 호출될 때 함수를 사용합니다. f를 매개변수로 사용하고 내부적으로 생성된 함수를 반환하므로 f는 decorator_a에서 반환된 inner_a를 참조합니다. 따라서 향후 f가 호출되면 실제로는 inner_a를 호출하는 것과 같습니다. f에 전달된 매개변수는 inner_a에 전달됩니다. inner_a를 호출하면 수신된 매개변수가 inner_a에 있는 func, 즉 f에 전달됩니다. 최종 반환은 f 값에 의해 호출되는 것이므로 외부에서는 f를 직접 다시 호출하는 것처럼 보입니다.
위의 두 개념이 명확해지면 가장 독창적인 예에서 무슨 일이 일어났는지 명확하게 알 수 있습니다.
인터프리터가 다음 코드를 실행하면 실제로 decorator_a 및 decorator_b를 아래에서 위로 순서대로 호출하고 해당 Get in decorator_a 및 Get in decorator_b가 출력됩니다. 이때 f는 decorator_b의 inner_b와 동일합니다. 하지만 f가 호출되지 않았기 때문에 inner_b가 호출되지 않았고, 비유적으로 inner_b 내부의 inner_a가 호출되지 않았으므로 Get in inner_a와 Get in inner_b가 출력되지 않습니다.
@decorator_b @decorator_a def f(x): print 'Get in f' return x * 2
그런 다음 마지막 줄에서 매개변수 1로 f를 호출하면 inner_b가 호출됩니다. 먼저 Get in inner_b를 인쇄한 다음 inner_b 내부에서 inner_a를 호출하므로 Get in inner_a가 인쇄됩니다. 원본 f는 inner_a 내부에서 호출되고 그 결과가 최종 결과로 반환됩니다. 이 시점에서 당신은 출력이 왜 그런 것인지 알아야 하고, 데코레이터 실행 시퀀스에서 실제로 무슨 일이 일어나는지 어느 정도 이해해야 합니다.
위 예제의 마지막 줄에서 f 호출을 제거하고 시연을 위해 repl에 넣으면 자연스럽게 순서 문제도 볼 수 있습니다.
➜ test git:(master) ✗ python Python 2.7.11 (default, Jan 22 2016, 08:29:18) [GCC 4.2.1 Compatible Apple LLVM 7.0.2 (clang-700.1.81)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> import test13 Get in decorator_a Get in decorator_b >>> test13.f(1) Get in inner_b Get in inner_a Get in f 2 >>> test13.f(2) Get in inner_b Get in inner_a Get in f 4 >>>
실제 적용 시나리오에서는
@login_required @permision_allowed def f() # Do something return
, 위의 방법을 사용하여 두 가지 장식 방법을 작성했습니다. 예를 들어 먼저 @login_required에 로그인했는지 확인한 다음 @permision_allowed 권한이 충분한지 확인합니다.
rrreee더 많은 Python 장식 장치의 실행 순서에 대한 신화와 관련된 기사는 PHP 중국어 웹 사이트에 주목하십시오!