(如果您想略过一些凌晨2点的Python科学知识,并追赶一下,我的问题将在最后总结)

考虑以下:

1: animals = ['cat', 'cow', 'donkey', 'horse']  # we start with a list
2: animals_reference = animals  # make another reference and assign it to animals

3: cat = animals[0]  # refer cat to first element of animals
4: assert cat is animals[0]  # no copy occurred, still same object

5: animals[0] = animals[0].capitalize()  # change first element of list
6: assert cat is not animals[0]  # animals[0] now refers to another object
7: assert animals_reference is animals  # animals still points to the same object as before


我的理解是,Python列表的底层结构是一个C数组(有很多动态的东西在进行,但最后还是一个C数组。)

令我感到困惑的是:我们将cat设置为引用列表的第一个元素(3)。在C语言中,将其引用为数组第一个元素的地址。

然后,我们修改列表的第一个元素(5)。

但是这样做之后,cat不再引用该对象(6)。但是,列表引用也没有改变,因为在(7)中我们看到它自开始以来就指向同一对象。

这让我很困惑,因为它暗示即使没有被重新分配,猫现在也指的是其他东西。

因此,我进行了以下实验:

cat = animals[0]  # refer cat to first element of animals
assert cat is animals[0]  # no copy occurred, still same object
print("id of cat:        {}".format(hex(id(cat))))
print("id of animals[0]: {}".format(hex(id(animals[0]))))
print("id of animals[]:  {}".format(hex(id(animals))))

print("capitalizing animals[0]...")
animals[0] = animals[0].capitalize()
print("-id of cat:        {}".format(hex(id(cat))))
print("-id of animals[0]: {}".format(hex(id(animals[0]))))
print("-id of animals[]:  {}".format(hex(id(animals))))


随着输出:

id of cat:         0xffdda580
id of animals[0]:  0xffdda580
id of animals[]:   0xffddc828
capitalizing animals[0]...
-id of cat:        0xffdda580  # stayed the same!
-id of animals[0]: 0xffe12d40  # changed!!
-id of animals[]:  0xffddc828


这使我相信Python列表不一定是内存的连续元素,对元素的更改将仅指向内存中的其他位置吗?我的意思是,数组第一个元素的地址在内存中早于数组本身的地址!

清单使用的基本结构到底是什么,可以解释我所看到的?

最佳答案

这是一种思考方式:

1: animals = ['cat', 'cow', 'donkey', 'horse']  # we start with a list
2: animals_reference = animals  # make another reference and assign it to animals

3: cat = animals[0]  # refer cat to first element of animals


这不会使cat指的是“动物的第一要素”,至少不是按照您的意思。它使cat引用动物的第一个元素所引用的内容。在这种情况下,即为字符串“ cat”。换句话说,表达式animals[0]本身是对对象的引用。该对象是字符串cat。当您执行animals[0]时,您将获得表达式animals[0]所引用的对象。当您执行cat = animals[0]时,将cat设置为引用该对象。

无法避免“取消引用”值animals[0]。也就是说,没有办法说“给我animals[0]的指向性,以便当animals[0]开始指向其他内容时,我的新变量也将指向其他内容”。您只能得到animals[0]所指的内容,而不能获得其指称性本身。

从而:

4: assert cat is animals[0]  # no copy occurred, still same object

5: animals[0] = animals[0].capitalize()  # change first element of list


在这里,您可以更改animals[0]指向的内容。但是您将cat设置为animals[0]所指向的对象。因此,现在catanimals[0]指向不同的地方。字符串"cat"不变(这就是为什么is测试仍然显示值相同的原因);只是animals[0]不再指向该字符串,而是开始指向字符串"Cat"

关于python - 用现有的元素引用修改列表?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31488199/

10-11 11:02