web-dev-qa-db-ja.com

デコレータの実行順序

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、反対の代わりに。

だから、これはほとんどのプログラミング言語のトップダウンアプローチの標準とは異なることを意味しますか?このデコレータの場合だけ?それとも私は間違っていますか?

70
Newbie

デコレータwrap装飾する機能。したがって、_make_bold_は、hello関数を装飾した_make_italic_デコレーターの結果を装飾しました。

_@decorator_構文は実際には単なる構文上の砂糖です。以下:

_@decorator
def decorated_function():
    # ...
_

実際に実行されます:

_def decorated_function():
    # ...
decorated_function = decorator(decorated_function)
_

元の_decorated_function_オブジェクトを、decorator()が返すものに置き換えます。

デコレータをスタックすると、そのプロセスが繰り返されますoutward

あなたのサンプル:

_@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()は、元のmake_italic()を呼び出すラムダでもあるhello()の戻り値であるラップされた関数_make_bold_を呼び出すlambdaを返しました。取得するこれらすべての呼び出しを展開します。

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

したがって、出力は次のようになります。

_"<b>" + ("<i>" + ("hello world") + "</i>") + "</b>"
_
94
Martijn Pieters