2012-07-08 64 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

相关问题