Python 这两者有区别吗?

Python 这两者有区别吗?,python,arrays,memory-management,immutability,Python,Arrays,Memory Management,Immutability,代码A: 代码B: lst = [1, 2, 3] for i in range(10): lst+= ["42"] 我知道输出是一样的,但是两个列表的构建方式有区别吗? 后面到底发生了什么事?当你这样做的时候 lst = [1, 2, 3] for i in range(10): lst = lst + ["42"] 您正在变异lst,并在其末尾添加“42”。但是当你说 lst += ["42"] 您正在使用lst和“42”创建一个新列表,并将新列表的引用分配给lst。请

代码A:

代码B:

lst = [1, 2, 3]
for i in range(10):
    lst+= ["42"]
我知道输出是一样的,但是两个列表的构建方式有区别吗? 后面到底发生了什么事?

当你这样做的时候

lst = [1, 2, 3]
for i in range(10):
    lst = lst + ["42"]
您正在变异
lst
,并在其末尾添加“42”。但是当你说

lst += ["42"]
您正在使用
lst
“42”
创建一个新列表,并将新列表的引用分配给
lst
。请尝试此程序以更好地理解这一点

lst = lst + ["42"]
前两个ID相同,但最后一个ID不同。因为,将创建一个新列表,并且
lst
现在指向该新列表

如果不知道这两者之间的区别,那么在函数内部将列表作为参数传递给函数并向其追加一项时,就会产生问题,如下所示

lst = ["1"]
print(id(lst))
lst += ["2"]
print(id(lst))
lst = lst + ["3"]
print(id(lst))
def mutate(myList):
    myList = myList + ["2"] # WRONG way of doing the mutation
tList = ["1"]
mutate(tList)
print(tList)
你仍然会得到
['1']
,但是如果你真的想改变
myList
,你可以这样做

lst = ["1"]
print(id(lst))
lst += ["2"]
print(id(lst))
lst = lst + ["3"]
print(id(lst))
def mutate(myList):
    myList = myList + ["2"] # WRONG way of doing the mutation
tList = ["1"]
mutate(tList)
print(tList)

将打印
['1',2']

您是否知道Python语言定义是否保证在您执行
lst=lst+[“3”]
时id将发生更改,或者这是否由实现来决定?我之所以这样问,是因为原则上Python的引用计数实现可能会注意到,
lst
在该操作开始时的refcount为1,并且被分配回其唯一的引用方,因此作为一种优化,我们希望重用该对象。当然,它可以重用用于数组的底层内存,但我想知道该语言是否允许它也重用
列表
本身。@SteveJessop据我所知,
id
的实现依赖于python实现。但是,在CPython中,我确信当我们执行该操作时,
id
将发生变化。因为,在CPython中,
id
返回对象的内存地址。因此,CPython上id更改的原因不是CPython使用地址作为id,而是它没有进行优化
id
必须为不同的对象返回不同的值,我的问题是Python实现是否允许为新对象提供与在同一语句中销毁的旧对象相同的地址(因为其refcount达到0)。