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因此被打破。

我是 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.

谢谢你。

更新二要回答我自己的第二个问题,不同之处似乎是在第一个代码(未显示)中使用了列表方法,而在第二个代码中则没有。

4

4 回答 4

4

正如其他人已经指出的那样,问题在于列表作为对函数的引用传递,因此函数体内的列表与您作为参数传递给它的对象完全相同。因此,您的函数执行的任何突变都可以从外部看到。

为了解决这个问题,您的algo函数应该对它传递的列表的副本进行操作。

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

from copy import deepcopy

def algo (X):
    X = deepcopy(X)
    ...
于 2012-07-08T09:42:17.703 回答
2

当你这样做时find_min(X),你将对象 X (在这种情况下是一个列表)传递给函数。如果该函数改变列表(例如,通过附加到它),那么是的,它将影响原始对象。Python 不会因为您将对象传递给函数而复制对象。

于 2012-07-08T09:32:38.787 回答
1

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

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

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

例如:

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

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

将打印:

['一种']

['一个','一个']

于 2012-07-08T09:33:52.343 回答
0

Python 列表是可变的(即,它们可以更改),并且函数调用algo中的使用确实会更改的值(即,它是列表的按引用传递)。例如,请参阅这个 SO questionfind_minX

于 2012-07-08T09:34:16.697 回答