2011-10-24 105 views
4

想象一下:這個Python裝飾函數的邏輯執行順序是什麼?

def b1(fnc): 
    print "b1" 
    return fnc 

@b1 
def a1(): 
    print "a1" 

if __name__ == "__main__": 
    a1() # will print b1 a1 

所以,當我使用@b1,A1被轉向a1 = b1(a1),對不對? 然後,當我說:

a1() 

這變成:

b1(a1) 

,然後進入:

print "b1" 
return fnc 

凡/究竟是誰打電話FNC?我有一種感覺,我在問一個非常愚蠢的問題,但我想明白。

回答

7

裝飾器只執行一次。它需要一個可調用對象並返回一個可調用對象。它返回的對象用於代替a1

換句話說,在定義a1時調用b1。它打印出"b1"並返回a1不變。由於它返回a1不變,因此b1在隨後調用a1時不起任何作用。

因此,下面的評論是不完全正確的:

a1() # will print b1 a1 

事實上,

  • a1()只打印"a1"
  • 您看到的"b1"@b1/def a1():打印。

如果更改像這樣並重新運行代碼,事件的順序應該更加清晰:

def b1(fnc): 
    print "b1" 
    return fnc 

@b1 
def a1(): 
    print "a1" 

if __name__ == "__main__": 
    print 'in __main__' 
    a1() 
    a1() 

最後,實現你要找的效果,裝飾將需要返回一個不同的可調用對象:

def b1(fnc): 
    def decorated(): 
    print "b1" 
    return fnc() 
    return decorated 

@b1 
def a1(): 
    print "a1" 

if __name__ == "__main__": 
    print 'in __main__' 
    a1() 
    a1() 

在這裏,很清楚誰叫fnc()

+0

關鍵的想法是,函數定義只是另一個被執行的代碼的和平(通常只有一次)。裝飾器只在執行函數定義時執行。 –

0

退房的How to make a chain of function decorators?

在,你會發現裝飾定義實際上是轉化的功能,並返回轉化功能最多的回答。這在裝飾時執行一次(當應用@ ...時)。在你給出的例子中,b1沒有定義轉換,但print語句仍然被執行。然後返回原始函數,因此a1不會被「重新定義」。然後b1裝飾器的動作對a1不起作用。

1

誰在撥打fnc

基本上,()後面a1代碼的最後一行。

那麼是怎麼回事?裝飾者是爲了改變功能的行爲。

所以當你裝飾一些東西的時候,會根據裝飾器返回的內容創建一個新的函數。這意味着當a1定義爲時,修飾器運行一次。下面是一個說明這樣一個例子:

print 'def b1' 
def b1(fnc): 
    print "b1" 
    return fnc 

print 'def a1' 
@b1 
def a1(): 
    print "a1" 

if __name__ == "__main__": 
    print 'main' 
    a1() # will print b1 a1 

這將打印:

def b1 
def a1 
b1 
main 
a1 

正如你所看到的,裝飾b1執行main之前被調用。

它返回一個函數實例,該實例被分配給別名a1,它可以像任何其他函數實例一樣使用。

這是什麼「呼叫運營商」()a1代碼的最後一行呢。

0

我們叫a1_prev,正在裝修前的a1功能,a1()變成

b1(a1_prev)() 

不僅b1(a1_prev),最後()是那些誰調用由b1返回func