2012-07-08 63 views
1

我對全局變量沒有用處,也從來沒有明確地定義過一個,但我似乎在我的代碼中有一個。你能幫我把它變成當地的嗎?爲什麼我的(本地)變量的行爲像一個全局變量?

def algo(X): # randomized algorithm 
    while len(X)>2: 
     # do a bunch of things to nested list X 
    print(X) 
    # tracing: output is the same every time, where it shouldn't be. 
    return len(X[1][1]) 

def find_min(X): # iterate algo() multiple times to find minimum 
    m = float('inf') 
    for i in some_range: 
     new = algo(X) 
     m = min(m, new) 
    return m 

X = [[[..], [...]], 
    [[..], [...]], 
    [[..], [...]]] 

print(find_min(X)) 
print(X) 
# same value as inside the algo() call, even though it shouldn't be affected. 

X似乎表現得像一個全局變量。隨機算法algo()在第一次調用時只執行一次,因爲X保留其更改後的值,因此它永遠不會在while循環內執行。 find_min中迭代的目的因此被擊敗。

我是新來的蟒蛇,甚至更新的論壇,所以讓我知道如果我需要澄清我的問題。謝謝。

更新非常感謝迄今爲止所有的答案。我幾乎瞭解它,除了我之前做過這樣的事情,結果更加快樂。你能解釋爲什麼下面的代碼不同嗎?

def qsort(X): 
    for ... 
     # recursively sort X in place 
     count+=1 # count number of operations 
    return X, count 

X = [ , , , ] 
Y, count = qsort(X) 
print(Y) # sorted 
print(X) # original, unsorted. 

謝謝。

更新II爲了回答我自己的第二個問題,差異似乎是在第一個代碼(未顯示)中使用列表方法,而在第二個代碼中缺少它。

回答

4

正如其他人已經指出的那樣,問題在於列表是作爲對函數的引用傳遞的,所以函數體內的列表與您作爲參數傳遞給它的那個對象是完全相同的對象。因此,您的功能發揮的任何突變都可從外部看到。

爲了解決這個問題,你的algo函數應該在它傳遞的列表的副本上運行。

當您在嵌套列表上操作時,應該使用copy模塊中的deepcopy函數來創建列表的副本,您可以自由變更列表的副本,而不影響功能以外的任何內容。內置的list函數也可用於複製列表,但它只創建淺拷貝,這不是您想要嵌套列表的內容,因爲內部列表仍然只是指向相同對象的指針。

from copy import deepcopy 

def algo (X): 
    X = deepcopy(X) 
    ... 
+0

謝謝。這很好。 – bongbang 2012-07-09 05:17:25

2

當你做find_min(X),你傳遞的對象X(在這種情況下是一個列表)的函數。如果該函數改變列表(例如,通過附加到它),那麼是的,它會影響原始對象。 Python不會因爲將它們傳遞給函數而複製對象。

1

當您將對象傳遞給一個python函數時,該對象不會被複制,而是傳遞一個指向該對象的指針。

這很有意義,因爲它大大加快了執行速度 - 在長列表的情況下,不需要複製其所有元素。

但是,這意味着當您修改傳遞的對象(例如,您的列表X)時,該修改適用於該對象,即使函數返回後。

例如:

def foo(x): 
    x.extend('a') 
    print x 

l = [] 
foo(l) 
foo(l) 

將打印:

[ '一']

[ '一個', 'A']

0

Python列表是可變的(即,他們可以改變)algo使用find_min函數調用確實更改值X (即,它是列表傳遞的參考)。例如,請參閱this SO question

相關問題