2008-12-14 43 views
55

有時似乎很自然有一個空列表的默認參數。但是Python在這些情況下會產生意想不到的行爲避免默認參數爲空列表的Python方法是什麼?

如果,例如,我有一個函數:

def myFunc(working_list = []): 
    working_list.append("a") 
    print working_list 

第一次被調用時使用默認的工作,但之後呼叫將使用一個不斷更新的名單。

那麼,什麼是pythonic的方式來獲得我想要的行爲(每個電話的新清單)?

+10

如果任何人的興趣在爲什麼出現這種情況,請http://effbot.org/zone/default-values.htm – 2012-07-16 19:06:36

+0

同樣的行爲發生了套,儘管你需要一個稍微複雜的例子來顯示它是一個bug。 – abeboparebop 2015-11-19 12:28:29

回答

81
def myFunc(working_list=None): 
    if working_list is None: 
     working_list = [] 
    working_list.append("a") 
    print working_list 

是我該怎麼做的。

11

這不是問題在這種情況下,但您可以使用對象標識來測試無:

if working_list is None: working_list = [] 

你也可以利用怎樣的布爾運算符或在Python定義:

working_list = working_list or [] 

雖然如果調用者爲working_list提供了一個空列表(其計數爲false),並且期望您的函數修改他提供的列表,但這種行爲會出乎意料。

1

我可能是脫離主題,但請記住,如果您只是想傳遞可變數量的參數,pythonic方式是傳遞一個元組*args或字典**kargs。這些是可選的,並且比語法myFunc([1, 2, 3])更好。

如果你想傳遞一個元組:

def myFunc(arg1, *args): 
    print args 
    w = [] 
    w += args 
    print w 
>>>myFunc(1, 2, 3, 4, 5, 6, 7) 
(2, 3, 4, 5, 6, 7) 
[2, 3, 4, 5, 6, 7] 

如果你想傳遞的字典:

def myFunc(arg1, **kargs): 
    print kargs 
>>>myFunc(1, option1=2, option2=3) 
{'option2' : 2, 'option1' : 3} 
8

如果該功能的目的是修改working_list傳遞的參數,請參閱HenryR的答案(=無,在裏面檢查無)。

但是,如果你不打算變異的說法,只是用它作爲出發點的列表,你可以簡單地複製:

def myFunc(starting_list = []): 
    starting_list = list(starting_list) 
    starting_list.append("a") 
    print starting_list 

(或在這個簡單的例子只是print starting_list + ["a"]但我猜這只是一個玩具的例子)

一般來說,變異你的參數是Python中的不良風格。唯一完全預期會改變對象的函數是該對象的方法。更改可選參數更爲罕見 - 僅在某些調用中發生的副作用纔是真正的最佳界面?

  • 如果您從「輸出參數」的C習慣這樣做,這是完全沒有必要的 - 你可以隨時返回多個值作爲一個元組。

  • 如果你這樣做,以有效地建立一個長列表的結果沒有建立中間名單,考慮寫作爲一個發電機,並使用result_list.extend(myFunc())當你打電話給它。這樣你的調用約定仍然非常乾淨。其中突變可選ARG

一種模式是經常做的是遞歸函數隱藏的「備忘錄」 ARG:

def depth_first_walk_graph(graph, node, _visited=None): 
    if _visited is None: 
     _visited = set() # create memo once in top-level call 

    return if node in _visited 
    _visited.add(node) 
    for neighbour in graph[node]: 
     depth_first_walk_graph(graph, neighbour, _visited) 
5

現有的答案已經提供了直接的解決方案要求。然而,由於這是一個新的Python程序員很常見的陷阱,值得補充爲什麼蟒蛇的行爲這樣解釋,這是很好的總結了「的漫遊指南到Python」爲「易變默認參數」:

報價:「Python的默認參數進行評估,一旦被定義的功能時,不會在每次調用函數時(就像是在說,紅寶石)這意味着,如果您使用的是可變的默認參數和變異它,你將和已經變異爲對該函數的所有未來調用該對象以及

示例代碼來實現它:

提供
def foo(element, to=None): 
    if to is None: 
     to = [] 
    to.append(element) 
    return to 
0

這兒已經好正確的答案。我只是想給另一種語法來寫你想做的事,我覺得更漂亮時,你比如想創建一個默認的空列表類的內容:

class Node(object): 
    def __init__(self, _id, val, parents=None, children=None): 
     self.id = _id 
     self.val = val 
     self.parents = parents if parents is not None else [] 
     self.children = children if children is not None else [] 

這段代碼利用了,如果其他運營商的語法。我喜歡它,特別是因爲它是一個沒有冒號的整齊的小單線,等等,它幾乎像一個正常的英語句子。 :)

你的情況,你可以寫

def myFunc(working_list=None): 
    working_list = [] if working_list is None else working_list 
    working_list.append("a") 
    print working_list 
相關問題