0

私は単純なデコレータを持っていますが、出力は私を混乱させました。

def deco(func):
   def kdeco():
      print("before myfunc() called.")
      func()
      print("  after myfunc() called.")
   return kdeco

@deco
def myfunc():
   print(" myfunc() called.")

myfunc()

before myfunc() called.
 myfunc( deco(myfunc)()) called.
  after myfunc() called.

deco(myfunc)()

before myfunc() called.
before myfunc() called.
 myfunc() called.
  after myfunc() called.
  after myfunc() called.

私は myfunc() の出力を知っていますが、deco(myfunc)() の出力は私を混乱させました。なぜ deco(myfunc)() の出力は次のどちらにもならないのですか?

ステータス 1:

before myfunc() called.
before myfunc() called.
 myfunc() called.
 myfunc() called.
  after myfunc() called.
  after myfunc() called.

ステータス 2:

before myfunc() called.
 myfunc( deco(myfunc)()) called.
  after myfunc() called.
before myfunc() called.
 myfunc( deco(myfunc)()) called.
  after myfunc() called.
4

3 に答える 3

4

myfuncそれ自体はすでにデコレーターによってラップされています。名前myfuncは元のメソッドを指すのではなく、deco(myfunc)次の戻り値を指すようになりました。

>>> def deco(func):
...    def kdeco():
...       print("before myfunc() called.")
...       func()
...       print("  after myfunc() called.")
...    return kdeco
... 
>>> @deco
... def myfunc():
...    print(" myfunc() called.")
... 
>>> myfunc
<function kdeco at 0x10068cb18>

これは、@decorator構文が次と同じであるためです。

def myfunc():
    # body of function
myfunc = deco(myfunc)

だからmyfunc、すでにラインを生産してbefore .... calledますafter ..もう一度ラップします。ラッパーは を出力し、ラップされた(それ自体はすでにラップされています)をbefore ..呼び出します。myfuncbefore .... calledafter ..after ..

図では:

call wrapped myfunc():
    kdeco: "before .."
    call original myfunc()
        original myfunc: ".. called"
    kdeco: "after .."

call deco(myfunc)():
    kdeco: "before .."
    call wrapped myfunc():
        kdeco: "before .."
        call original myfunc()
            original myfunc: ".. called"
        kdeco: "after .."
    kdeco: "after .."
于 2013-01-16T00:26:30.520 に答える
1

装飾された関数は 1 回だけ呼び出されるため、2 回呼び出されたと主張することはできません。

于 2013-01-16T00:24:36.180 に答える
1

デコレーターは、実際には、手動でできることへのショートカットにすぎません。このコード:

@deco
def myfunc():
    print(" myfunc() called.")

以下と同等です。

def myfunc():
    print(" myfunc() called.")
myfunc = deco(myfunc)

これを議論するために、オリジナルがまだ利用可能であったとしましょうoriginal_myfunc(実際にはそうではありませんが)。

したがって、これを行うと:

deco(myfunc)()

最終的に呼び出すのは次のとおりです。

deco(deco(original_myfunc))()

そして、それをたどると、期待どおりに出力される理由が明らかになるはずです。とにかく運動をしましょう。

まず、 を呼び出すと、次のようdeco(original_myfunc)になります。

def kdeco():
   print("before myfunc() called.")
   original_myfunc()
   print("  after myfunc() called.")

kdeco を返す

そのため、「前」を出力する関数が返され、 が呼び出さoriginal_myfuncれ、「後」が出力されます。

そしてdeco(original_myfunc)deco再び に渡します。これは次のことを行います:

def kdeco():
   print("before myfunc() called.")
   deco(original_myfunc)()
   print("  after myfunc() called.")
return kdeco

したがって、それは「前」を出力してから呼び出す関数を返しますdeco(original_myfunc)—それ自体が「前」を出力し、 を呼び出しoriginal_myfuncて「後」を出力します—次に「後」を出力します。

それが、あなたが行う出力を得る理由です。

于 2013-01-16T00:26:48.930 に答える