具有列表的Python实例行为

具有列表的Python实例行为,python,python-3.x,list,Python,Python 3.x,List,考虑Python中的以下实例行为 def change(elements): elements[0] = 888 elements = [-3, -1, -2, -3, -4] print(elements[0]) numbers = [1, 4, 5] print(numbers[0]) change(numbers) print(numbers[0]) print(numbers) 下面的Python代码片段打印 1 -3, 888 [888,4,5] 它

考虑Python中的以下实例行为

def change(elements):
    elements[0] = 888
    elements = [-3, -1, -2, -3, -4]
    print(elements[0])

numbers = [1, 4, 5]

print(numbers[0])
change(numbers)
print(numbers[0])
print(numbers)
下面的Python代码片段打印

1
-3, 
888 
[888,4,5]
它不应该打印吗

1, 
-3, 
-3, 
[-3,-1,-2,-3,-4]

为什么列表中的一个元素会被成功覆盖,而不是整个列表对象?

列表作为引用传递给函数。因此,该列表在全局空间和函数之间共享。第一个更改将修改列表,该更改将反映在两个空间中。但是,您需要执行并分配给列表变量。这将在函数中创建一个新列表。原始列表存在于全局空间中,但它不再存在于函数中。因此,从该点开始对函数中的列表所做的所有更改仅在函数中可见


考虑此实例的另一种方式是,列表是一种容器类型。函数的第一行更改容器中的内容。第二行(赋值)实际上更改了您正在使用的容器。这不仅适用于列表,也适用于任何对象。这就是@Chris_Rands在评论中给出的解决方案起作用的原因:它修改容器中的内容,而不更改容器。

更改
函数中,首先使用外部范围中的
元素,作为参数传递并被引用的-可以在函数中更改,更改的内容将影响对象,甚至超出局部范围

然后创建
元素的本地实例
,修改它并结束函数。由于先前更改了全局范围中的
元素
,因此您会看到“意外”结果


查看更多详细信息。

这是一个典型的Python变量命名参考混淆。我真正想做的是理解,尽管是打印一个参考,看看发生了什么

def change(elements):
    elements[0] = 888
    print("ID of elements is: %d",id(elements))
    elements = [-3, -1, -2, -3, -4]
    print("ID of elements is: %d",id(elements))
    print(elements[0])

numbers = [1, 4, 5]
print("ID of number is: %d",id(numbers))

print(numbers[0])
change(numbers)
print(numbers[0])
print(numbers)

>>>> ('ID of number is: %d', 140036366181584)
1
('ID of elements is: %d', 140036366181584)
('ID of elements is: %d', 140036366181944)
-3
888
[888, 4, 5]
这里的ID代表内存中的一个位置。如果您运行代码,数字可能不同,但行为保持不变

基本上,当你打电话的时候

 elements[0] = 888
实际上,您正在变异
数字
(与我的示例中的
14003636181584
的ID相同)

但是,当你打电话的时候

elements = [-3, -1, -2, -3, -4]
您正在创建一个新列表(在我的示例中,不同的ID为
14003636181944
),并将本地名称
元素重新分配给它。您只是将名称
元素
分配给另一个对象。它不再是同一个列表了


因此,在这一点上,您对数字所做的一切就是用值
888
更改其第一个索引,这就是输出的经验显示

不应该,因为第一行覆盖参数
元素的第一个值,第二行为函数定义新的局部变量。

查看ID将使理解

def change(elements):
    print('inner first elements ID ',id(elements))
    elements[0] = 888
    print('inner second elements ID ',id(elements))
    elements = [-3, -1, -2, -3, -4]
    print('inner third elements ID ',id(elements))
    print('inner third numbers ID ',id(numbers))

numbers = [1, 4, 5]
print(numbers[0])
print('outer numbers ID ',id(numbers))
change(numbers)
print('c ',numbers[0])
print('d', numbers)

元素[:]=[-3,-1,-2,-3,-4]
将产生您预期的输出…阅读此内容将消除您的误解:@Chris_Rands:是的,但没有解释为什么OP不能更好地理解语言。关键区别在于
elements=somelist
是简单的赋值,只是将本地名称重新绑定到另一个对象,而
elements[:]=somelist
看起来只是赋值。对于调用现有对象上的mutating方法来说,这真的是一种语法上的甜点,该对象被称为name
elements
。谢谢大家,这些都是很好的注释。“Pass by reference”带来的包袱对于Python来说并不十分正确(但它已经足够好了)。“通过赋值传递”已成为一种流行的描述方式,因为它遵循Python赋值的语义。@StevenRumbalski感谢您指出这一点。我并没有真正考虑对对象的引用和对内存的引用之间的区别,但这是有意义的。我今天也学到了一些新东西!:)