2016-04-05 31 views
3

我有下面的裝飾器演示代碼。如果我在沒有明確調用greet函數的情況下執行它,它將在裝飾器函數內執行print語句並輸出Inside decoratorPython裝飾器函數執行

我無法理解裝飾者的這種行爲。即使我沒有撥打greet函數,如何調用time_decorator

我使用Python 3

def time_decorator(original_func): 
    print('Inside decorator') 
    def wrapper(*args, **kwargs): 
     start = time.clock() 
     result = original_func(*args, **kwargs) 
     end = time.clock() 
     print('{0} is executed in {1}'.format(original_func.__name__, end-start)) 
     return result 
    return wrapper 


@time_decorator 
def greet(name): 
    return 'Hello {0}'.format(name) 

回答

1

裝飾被稱爲在開始時間(當在程序啓動Python解釋器讀取的代碼),而不是在運行(當裝飾功能實際上被稱爲)

在運行時,它是被調用的包裝函數wrapper,它本身調用裝飾函數並返回其結果。

所以這是完全正常的,print行被執行。

如果你裝飾了10個功能,你會看到10倍的打印輸出。無需爲此發生調用裝飾函數。

print移到wrapper之內,這樣就不會再發生了。

Decorators以及metaclasses是所謂部分元編程(修改/創建代碼,從現有的代碼)。這是編程的一個非常吸引人的方面,需要時間來理解,但提供了驚人的可能性。

+0

謝謝@Apero!在編譯時調用裝飾器的動機是什麼?除了裝飾器之外,是否有任何在編譯期間被調用的對象? –

+0

是的,元類在編譯時修改它們是「元類」的類,而不是在運行時。元類和裝飾器可以像代碼黑客一樣成爲代碼,因爲它們修改分別元類或裝飾的代碼,而不必修改初始代碼本身。然後每當這個「現在的代碼」被調用時,新的黑客行爲就會發生。 –

+0

我認爲說「編譯時間」頗具誤導性。 Python函數(和類)定義由解釋器在運行時(例如,當您啓動程序時)運行的語句創建,而不是在較早的時間(如Java或C程序)。有一個涉及Python代碼(從源代碼到字節碼)的編譯步驟,但這與執行像'def'這樣的語句無關。 – Blckknght

4

time_decorator在功能修飾期間執行。 wrapper不是(調用裝飾greet()時調用此函數)。

@只是語法糖。以下代碼片段是等效的。

裝飾語法:

@time_decorator 
def greet(name): 
    return 'Hello {0}'.format(name) 

明確裝修過程 - 裝飾是返回基於另外一個新功能的功能。

def greet(name): 
    return 'Hello {0}'.format(name) 

greet = time_decorator(greet)