为什么我的(本地)变量表现得像全局变量?

时间:2012-07-08 09:27:15

标签: python list global-variables

我没有使用全局变量,也没有明确定义一个,但我似乎在我的代码中有一个。你能帮我把它变成当地的吗?

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中迭代的目的被打败了。

我是python的新手,甚至是这个论坛的新手,所以如果我需要澄清我的问题,请告诉我。感谢。

更新非常感谢到目前为止的所有答案。我几乎理解它,除了我之前做过类似的事情,结果更快乐。你能解释为什么下面这段代码不同吗?

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 要回答我自己的第二个问题,差异似乎是在第一个代码(未显示)中使用list方法,而在第二个代码中缺少list方法。

4 个答案:

答案 0 :(得分:4)

正如其他人已经指出的那样,问题是列表是作为函数的引用传递的,因此函数体内的列表与作为参数传递给它的那个对象是完全相同的对象。因此,从外部可以看到你的功能所发生的任何突变。

要解决此问题,您的algo函数应该对其传递的列表副本进行操作。

当您在嵌套列表上操作时,您应该使用deepcopy模块中的copy函数创建列表的副本,您可以自由变异而不会影响函数之外的任何内容。内置的list函数也可用于复制列表,但它只创建浅拷贝,这不是嵌套列表所需的,因为内部列表仍然只是指向相同对象的指针。

from copy import deepcopy

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

答案 1 :(得分:2)

执行find_min(X)时,您将对象X(本例中为列表)传递给函数。如果该函数改变了列表(例如,通过附加它),则是,它将影响原始对象。 Python不会仅仅因为将对象传递给函数而复制对象。

答案 2 :(得分:1)

将对象传递给python函数时,不会复制该对象,而是传递指向该对象的指针。

这是有道理的,因为它大大加快了执行速度 - 在长列表的情况下,不需要复制其所有元素。

但是,这意味着当您修改传递的对象(例如,列表X)时,即使在函数返回后,修改也会应用于该对象。

例如:

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

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

将打印:

[ '一']

['a','a']

答案 3 :(得分:0)

Python列表是可变的(即,它们可以更改)并且在algo函数调用中使用find_min更改X的值(即,它是列表的传递参考)。例如,请参阅this SO question