데코레이터 실행 순서


96
def make_bold(fn):
    return lambda : "<b>" + fn() + "</b>"

def make_italic(fn):
    return lambda : "<i>" + fn() + "</i>"

@make_bold
@make_italic
def hello():
  return "hello world"

helloHTML = hello()

산출: "<b><i>hello world</i></b>"

나는 대략적으로 데코레이터에 대해 이해하고 대부분의 예제에서 데코레이터 중 하나와 어떻게 작동하는지 이해합니다.

이 예에는 2 개가 있습니다. 출력에서 @make_italic먼저 실행되고 @make_bold.

이것은 데코 레이팅 된 함수의 경우 먼저 함수를 먼저 실행 한 다음 다른 데코레이터를 위해 맨 위로 이동한다는 것을 의미합니까? 그 반대 대신에 @make_italic처음 처럼 @make_bold.

그래서 이것은 대부분의 프로그래밍 언어에서 하향식 접근 방식의 표준과 다르다는 것을 의미합니까? 이 데코레이터의 경우에만? 아니면 내가 틀렸나 요?


4
예는 다음에 결과를 전달 아래에서 위로 시작
Padraic 커닝햄

1
@PadraicCunningham 코멘트도 답변의 중요한 부분입니다. 관련 문제가 있음 ( stackoverflow.com/questions/47042196/… )
shookees

나는 그것이 하향식이라는 의미에서 여전히 하향식이라고 말하고 싶습니다 a(b(x))(3 줄로 나뉘 었다고 상상한다면)
joel

답변:


130

데코레이터 는 자신이 꾸미는 기능을 래핑 합니다. 그래서 데코레이터 make_bold의 결과 make_italic를 장식하여 hello기능 을 장식했습니다 .

@decorator구문은 정말 그냥 문법 설탕입니다; 다음과 같은:

@decorator
def decorated_function():
    # ...

실제로 다음과 같이 실행됩니다.

def decorated_function():
    # ...
decorated_function = decorator(decorated_function)

원래 decorated_function개체를 decorator()반환 된 항목으로 대체합니다 .

데코레이터를 쌓아 올리는 것은 바깥쪽으로 처리하는 과정을 반복합니다 .

따라서 샘플 :

@make_bold
@make_italic
def hello():
  return "hello world"

다음으로 확장 할 수 있습니다.

def hello():
  return "hello world"
hello = make_bold(make_italic(hello))

당신이 호출 할 때 hello()지금, 당신은에 의해 반환 된 객체를 호출 make_bold()정말. make_bold()반환 된 lambda함수 호출 그 make_bold반환 값이다 싸서 make_italic()또한 원래 호출 람다이다 hello(). 이러한 모든 호출을 확장하면 다음과 같은 이점이 있습니다.

hello() = lambda : "<b>" + fn() + "</b>" #  where fn() ->
    lambda : "<i>" + fn() + "</i>" # where fn() -> 
        return "hello world"

따라서 출력은 다음과 같습니다.

"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"

이해 했어요. 그러나 이것은이 경우에 2 개의 래퍼가있을 때 IDE가 첫 번째 래퍼의 결과를 자동으로 감지하고 래핑한다는 것을 의미합니까? 내가 그렇게 생각했기 때문에 @make_bold #make_bold = make_bold(hello) @make_italic #make_italic = make_italic (hello)? 이것을 기반으로 첫 번째 결과를 래핑할지 확실하지 않습니다. 또는이 래퍼가 2 개인 경우 IDE는 make_bold(make_italic(hello))내가 공유 한 내용 대신 언급 한대로 사용합니까?
Newbie

3
@Newbie : IDE는 여기서 아무것도하지 않습니다. 랩핑을 하는 것은 파이썬 입니다. 나는 나의 마지막 샘플에서 당신을 보여 주었다 make_bold()의 출력 랩 make_italic()포장하는 데 사용되었다 hello에 해당하므로 make_bold(make_italic(hello)).
Martijn Pieters

람다를 사용하지 않고이 코드의 버전을 제공 할 수 있습니까? .format을 시도했지만 작동하지 않습니다. 그리고 왜 람다가이 예에서 사용됩니까? 이 예제에서 람다와 그것이 어떻게 작동하는지 이해하려고 노력하고 있지만 여전히 문제가 있습니다. 람다는 def 함수의 표준에 비해 훨씬 쉽게 전달할 수있는 한 줄 함수와 같다는 것을 알 수 있습니다.
Newbie

def inner: return "<b>" + fn() + "</b>", 그러면 return inner'일반'함수 버전이됩니다. 그다지 큰 차이는 아닙니다.
Martijn Pieters

나는 항상 주문에 대해 혼란스러워합니다. "... 데코레이터는"def "문에 가장 가까운 것부터 적용됩니다." 저는 이것을 "inside-out"이라고 부릅니다. 나는 Martijn이 이것을 "외부"라고 부른다고 생각합니다. 이 수단의 make_italic 장식은 전에 실행되어 make_bold 장식 때문에 make_italic받는 가장 가까운 def. 그러나 데코 레이팅 된 코드 실행 순서를 잊어 버렸습니다. 데코 레이팅 make_bold (예 : 굵은 람다) 먼저 실행 된 다음 make_italic 데코 레이팅 된 람다 (예 : 기울임 꼴 람다)가 실행됩니다.
The Red Pea
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.