2014-09-05 58 views
1

我有一個類似於下面的代碼:__init__功能似乎是在定義執行,沒有實例

class thingy(object): 
    def __init__(creds=get_credentials()): 
     # does stuff 
     pass 

def get_credentials(): 
    # produces different values sometimes. Ie: retrieves values from a db 
    return db.get(some_query) 

dc.connect(credentials_and_stuff) 

這失敗進口,不運行時,定義__init__(),說「數據庫沒有連接」 。這對我沒有意義,因爲__init__()函數還沒有運行!

回答

4

我發現這一點:http://docs.python-guide.org/en/latest/writing/gotchas/#mutable-default-arguments

事實證明,對於可選參數值在他們定義執行時進行評估,。這是一個極端的例子:

def default_value(): 
    print("ERMAGERD DIS FUNCTION WAS RUN!") 
    return False 

def fake_function(an_arg=default_value()): 
    pass 

在這個發現之前,我會說這個代碼什麼都不做;沒有功能運行,只是一些定義。現在我知道(並經過測試),單單這個代碼將打印出ERMAGERD DIS FUNCTION WAS RUN!

這意味着在上述問題的代碼兩件事情:

  1. 爲了不會崩潰,在db.connect()將有class thingy(object)定義發生之前運行。
  2. get_credentials()只會得到運行一次,並表示DB查詢將永遠不會再運行(陳舊憑證!)

因此,爲了使這個實際上做什麼它打算做(查詢數據庫在沒有提供憑據時),你必須做一些類似於此:

class thingy(object): 
    def __init__(creds=None): 
     if creds is None: 
      creds = get_credentials() 
     # does stuff 
     pass 

這樣get_credentials()在運行時運行,而不是在定義。這兩個都允許db.connect()在其他地方完成(只要它在實例化thingy的實例之前),修復陳舊憑證問題。

+1

看看本教程的初始章節([Default Argument Values](https://docs.python.org/3/tutorial/controlflow.html#default-argument-values)):「默認值是在_defining_範圍內的函數定義處評估的「。這看起來像很基礎的知識。 – Matthias 2014-09-05 20:21:23

+0

你可以說它是基本的知識,但我不覺得這是足夠明顯的扔掉,不應該再次聲明。在遇到生產環境中引發的問題之前,我一直認爲可選參數是一種語法糖,它是作爲函數體的一部分執行的,語法或文檔中沒有任何內容(外部教程像你提到的那樣,但並非所有的教程都涵蓋了這個,我個人從來沒有使用過),在別處導致我認爲我錯了。 – Conslo 2014-09-05 22:04:46