列表在Python中通过引用混淆传递

时间:2017-05-20 00:34:29

标签: python list reference

我有这段代码只能对保证介于0和R-1(含)之间的数字列表进行排序。以下代码正确排序,但我不明白为什么传入的输入仍未修改。

def bucket(arr, R):
    assert type(arr) is list
    for i in arr:
        assert i >=0 and i < R
    b = [0] * R
    for i in arr:
        b[i]+=1
    arr = []
    for ind, v in enumerate(b):
        arr = arr + [ind] * v
    print(arr)

为什么在调用函数后,此示例中的inp保持不变:

>>> inp
[3, 1, 4, 5, 4, 5, 5, 5, 1, 5]
>>> bucket(inp, 8)
[1, 1, 3, 4, 4, 5, 5, 5, 5, 5]
>>> inp # unchanged, why?
[3, 1, 4, 5, 4, 5, 5, 5, 1, 5]

3 个答案:

答案 0 :(得分:2)

因为您在行arr中创建了一个名为arr = []的新变量,从此时开始操作新列表。同样,您始终使用for操作在以下arr = arr + [ind] * v循环内创建新列表。

您只需将其更改为:

def bucket(arr, R):
    assert type(arr) is list
    for i in arr:
        assert i >= 0 and i < R
    b = [0] * R
    for i in arr:
        b[i] += 1
    arr[:] = []  # remove all items from the list (in-place)
    for ind, v in enumerate(b):
        arr.extend([ind] * v)  # extend the list in-place, you could also use "arr += [ind] * v"
    print(arr)

示例:

>>> inp = [3, 1, 4, 5, 4, 5, 5, 5, 1, 5]
>>> bucket(inp, 8)
[1, 1, 3, 4, 4, 5, 5, 5, 5, 5]
>>> inp
[1, 1, 3, 4, 4, 5, 5, 5, 5, 5]

答案 1 :(得分:1)

通过将[]分配给arr,您将丢失对现有数组的引用,并创建一个新数组。

要更改它,您可以使用

inp.sort()

More info on sort vs sorted

答案 2 :(得分:0)

Python通过赋值传递,语义与Java的值传递极为相似。

因为您按值传递指针而产生混淆。这意味着您无法修改函数内部的指针,但没有人可以阻止您修改指向的指针(即数据)所以,例如:

x = 3
def change_x(x):
    x = 5
    return x
change_x(x)
print x
# Outputs 3

函数外部的x值(在本例中为3)在x进入函数之前被复制,因此赋值不执行任何操作。这通常是我们听到价值传递时的预期。

x = [1,2,3]
print(id(x))
# Outputs some "address"
def change_x(x):
    x.clear()
    x.extend([4,5,6])
    print(id(x))
    # Outputs the SAME address as above
    return x
change_x(x)
print(x)
# Outputs [4,5,6]

哎呀。我以为我们只是说我们无法改变x。问题是我们没有改变x!我们只是改变了x指向的数据(这里有一个微妙但重要的区别)。 x仍然是同一个指针。请注意,id输出的地址是相同的。

x = [1,2,3]
print(id(x))
# Outputs some "address"
def change_x(x):
    x = [4,5,6]
    print(id(x))
    # Outputs some DIFFERENT "address". The pointer to x was changed (inside this function).
    return x
change_x(x)
print(x)
# Outputs [1,2,3]

它在传入之前复制了x的值(指针值,而不是数据被复制)。所以,再次重新分配什么都不做。请注意,id函数此次输出不同的值。所以在函数返回之后,我们得到x的原始值(指针的原始值,即)