python 動態預設參數, 執行期

python 動態預設參數, 執行期 本文的內容是參考 《Effective Python》: tips 20
我們在 python 定義一個 function 時,如果想要給定 default argument 可以這樣寫:
def foo(arg=10):
    ... processing arg ...
但是如果我們今天要使用的預設參數是在動執行期才能夠決定的,而不是靜態時期該怎麼做呢? 例如:我們想要寫一個 log function, 會印出當時訊息的時間, 跟訊息內容
def log(msg, when=datetime.now()):
    print("{when}: {msg}".format(when, msg))
可是如果我們是用上面的寫法,會發現取到的時間都是一樣的,那是 function 被定義的時間。為了處裡這個問題,我們會先將它設置為 None 再做進一步的處理,然後再利用 docstring 來補充說明 default argument 的用處。
def log(msg, when=None):
    """
    when 的預設值是 function call 發生的時間,也就是 log message 的時間
    """
    when = datetime.now() if when is None else when
    ... print message ...
因為 default argument 只會被 evaluate 計算一次,所以如果我們使用 [], {} 做為我們的 default argument 有時候會出現不可預期的錯誤。 例如:
def to_json(data, default={}):
    try:
        return json.loads(data)
    except ValueError:
        return default
        
json_data1 = to_json('123 321')
json_data1['k1'] = 1

json_data2 = to_json('321 123')
json_data2['k2'] = 2

print(json_data1)
print(json_data2)
上面這段 code 我們預想 json_data1, json_data2 經由觸發 except 所得到的 dict 應該是 {} 且是不同的物件,但是他們卻是相同的!
如果你使用 [] 作為 default arguments 也會出現相似的錯誤! 這時候,我們的修正方式也是將他們先設置為 None 在 return 物件

留言

這個網誌中的熱門文章

Vim 自動 補完 插件 YouCompleteMe 教學 心得 新手入門 C++ C

怎麼建立一個 Https server?

Build Starcraft Learning Environment (using TorchCraft) 中文教學