1. ホーム
  2. python

[解決済み] デコレータの実行順序

2022-08-17 17:34:18

質問

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>"

私はデコレータについて、また、ほとんどの例でそのうちの1つを使ってどのように動作するかについて、おおよそ理解しています。

この例では、2つあります。出力から、どうやら @make_italic が最初に実行され、次に @make_bold .

これは、装飾された関数に対して、まずその関数を実行し、その後、他の装飾のために先頭に移動するということでしょうか?例えば @make_italic が最初に実行され、次に @make_bold というように、逆ではなく

ということは、ほとんどのプログラミング言語におけるトップダウンアプローチの規範とは異なるということでしょうか。このデコレータの場合だけ?それとも、私が間違っているのでしょうか?

どのように解決するのですか?

デコレータ ラップ というように、デコレートする関数を指定します。そのため 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>"