发现一个 Python bug,最初以为是引用问题,后来逐步 print 看还真是 bug

2024-05-10 00:10:51 +08:00
 llsquaer

列表字典中 随机一个字典增加 key ,再放入新列表中。出现预期不符。 直接上代码

有 bug 的情况

aaa = [
    {'id': 35,'src':'xxx'},
    {'id': 36,'src':'xxx'},
    {'id': 37,'src':'xxx'},
    {'id': 38,'src':'xxx'},
]

combinations = []

for i in range(5):
    cname = f'张三-{i}'
    ccc = random.choice(aaa)
    ccc.update({'cname': cname})
    print(ccc)                  # 这里的结果符合预期

    combinations.append(ccc)

print(combinations)             # 但是这里就错了

返回结果

{'id': 37, 'src': 'xxx', 'cname': '张三-0'}
{'id': 38, 'src': 'xxx', 'cname': '张三-1'}
{'id': 35, 'src': 'xxx', 'cname': '张三-2'}
{'id': 38, 'src': 'xxx', 'cname': '张三-3'}
{'id': 36, 'src': 'xxx', 'cname': '张三-4'}
# 以上 print 结果是对的

[{'id': 37, 'src': 'xxx', 'cname': '张三-0'}, {'id': 38, 'src': 'xxx', 'cname': '张三-3'}, {'id': 35, 'src': 'xxx', 'cname': '张三-2'}, {'id': 38, 'src': 'xxx', 'cname': '张三-3'}, {'id': 36, 'src': 'xxx', 'cname': '张三-4'}]
# 但是这里打印新生成的 combinations 列表就出现两个 `张三-3` 

改代码

后来想起来是引用对象问题,需要浅复制下.即只需要将 ccc = random.choice(aaa)改为ccc = random.choice(aaa).copy() 就符合预期了.

bug 的疑问

bug 问题在于示例里,单个 print 结果和添加到列表里的结果不一致.

python 版本 3.10.8

5364 次点击
所在节点    Python
55 条回复
cyrivlclth
2024-05-10 08:49:38 +08:00
钓鱼司马
anzu
2024-05-10 08:56:26 +08:00
既然你觉得最后打印 combinations 的结果是错的,那么就应该也在 for 循环中打印 combinations 的值,观察其是怎么变化的。
FYFX
2024-05-10 09:07:03 +08:00
你打印 ccc 的时候获得是当前 ccc.__repr__()的值,让后放到 combinations 里的 ccc 只是引用,后面修改了这个 ccc 之后再 print 的结果就是不一样啊
theprimone
2024-05-10 09:13:25 +08:00
@phrack 大多数语言都有这个问题吧,有语言层面默认 immutable 的吗?
accelerator1
2024-05-10 09:14:06 +08:00
进来之前就能猜到 LZ 要被群嘲了
superrichman
2024-05-10 09:15:52 +08:00
把 id 打出来,你会发现其实有多个 id 一样的元素,他们指向同一个对象

print([id(x) for x in combinations])

学一下 c 的指针就能理解了
Kinnice
2024-05-10 09:34:13 +08:00
如果你不是某个语言的 Master ,那你遇到的不符合你的理解的现象,基本都是你的理解不到位.
InkStone
2024-05-10 09:37:37 +08:00
Python 的作用域规则跟 C 不一样,cname 在出了 for 循环之后还是一个有效的对象,在下一次 for 循环中做的事情不是重新绑定了这个对象,而是修改了这个对象的值。
InkStone
2024-05-10 09:38:42 +08:00
@theprimone Rust 呀
mogita
2024-05-10 09:47:45 +08:00
一个观察不一定不准,发现了各个语言 bug 的新手,多半是来到了作用域的门前。
theprimone
2024-05-10 10:17:21 +08:00
@InkStone #29 这样啊,写过 Rust 的 Hello World ,还不知道这么硬核呢
djangovcps
2024-05-10 10:20:38 +08:00
能怀疑语言的内置容器有 bug ,我是没想到的
HashV2
2024-05-10 10:32:46 +08:00
没有问题 循环内的打印对象在后续的循环过程中被修改了
mylifcc
2024-05-10 10:38:23 +08:00
我是鱼
visper
2024-05-10 10:46:26 +08:00
鱼,好大的鱼,虎纹鲨鱼
hooych
2024-05-10 10:47:28 +08:00
代码执行的顺序并非是严格遵守代码逻辑的顺序,在不发生相关冲突的情况下,会发生顺序调整以优化性能。
1018ji
2024-05-10 10:55:20 +08:00
好大的 bug
agegcn
2024-05-10 11:12:03 +08:00
不符合预期就是 python 的 bug 。太自信了
CloveAndCurrant
2024-05-10 11:12:39 +08:00
{'id': 38, 'src': 'xxx', 'cname': '张三-1'}、{'id': 38, 'src': 'xxx', 'cname': '张三-3'}这两个其实指向的是同一个字典,你更改一个,相当于都改了,字典的.copy()方法是浅拷贝,浅拷贝后就是指向不同的字典了。
Goooooos
2024-05-10 11:18:00 +08:00
OP 可能真不适合编程。状态值都不懂。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/1039277

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX