2013-08-05 77 views
4

我希望熟悉Python編譯/運行時過程的人能夠對我關於Python如何編譯修飾器函數的問題提供一些啓示。Python編譯器函數在編譯時調用

在我的示例代碼中,我已經在定義了logtofile閉包之前在「writeit」裝飾器中包含了一個測試打印語句。如果運行我提供的完整代碼,writeit中的「測試」打印語句將在客戶類中定義的每個@writeit裝飾器調用 - 在使用writeit之前。

爲什麼在編譯時調用logtofile?有人可以解釋這種行爲嗎?

def writeit(func): 
    print('testing') 

    def logtofile(customer, *arg, **kwargs): 
     print('logtofile') 
     result = func(customer, *arg, **kwargs)   
     with open('dictlog.txt','w') as myfile: 
      myfile.write(func.__name__) 
     return result 

    return logtofile 

class Customer(object): 
    def __init__(self,firstname,lastname,address,city,state,zipcode):   
     self._custinfo = dict(firstname=firstname,lastname=lastname,address=address,city=city,state=state,zipcode=zipcode)   

    @writeit 
    def setFirstName(self,firstname): 
     print('setFirstName') 
     self._custinfo['firstname']=firstname 

    @writeit 
    def setLastName(self,lastname): 
     print('setLastName') 
     self._custinfo['lastname']=lastname 

    @writeit 
    def setAddress(self,address): 
     print('setAddress') 
     self._custinfo['address']=address 

def main(): 
    cust1 = Customer('Joe','Shmoe','123 Washington','Washington DC','DC','12345') 
    cust1.setFirstName('Joseph') 
    cust1.setLastName('Shmoestein') 

if(__name__ == '__main__'): main() 
+0

它不在編譯時,它在運行時。但是在類定義中運行'def'語句需要運行修飾它們的裝飾器。 – geoffspear

回答

6

您的代碼在模塊爲的情況下運行。 Python執行所有頂級語句,包括當時的類定義。

類定義主體是作爲一個函數執行的,局部名稱空間成爲類屬性。這意味着只要在模塊的頂層定義了類,就可以在導入時執行類體。

當Python在執行時遇到裝飾函數時,它將定義類,然後執行裝飾器函數,傳遞函數對象並將裝飾器的返回值綁定到函數的名稱。由於類體在導入期間被執行,這意味着您的裝飾器在那個時候被執行。

+0

謝謝你澄清,Martijn。你能推薦一些我可以用來更詳細地學習的參考資料嗎? – Dowwie

+0

你必須通讀[Python參考](http://docs.python.org/2/reference/);在[執行模型](http://docs.python.org/2/reference/executionmodel.html)中記錄了一個模塊在導入時被初始化,以及如何在['class'化合物中指定類的定義聲明](http://docs.python.org/2/reference/compound_stmts.html#class-definitions)參考。如何應用裝飾器是[函數定義](http://docs.python.org/2/reference/compound_stmts.html#function-definitions)參考的一部分。 –

1

沒有編譯時間。一個def語句和關聯的裝飾器調用是可執行語句。

因此,當Python加載模塊時,它會按順序執行語句。在執行類語句時,其中一個早期階段是執行類體中的所有語句。作爲那個def的一部分,運行它來創建函數,並且這些函數對象將被傳遞給裝飾器進行處理。

無論何時調用裝飾器,您的「測試」打印語句都會運行,而不是在調用它返回的函數時運行。如果你想要這種行爲,請將裝飾器移動到內部函數中。