你们说 Python 这个是 Bug 还是 Feature?

2022-08-30 15:44:32 +08:00
 lanlanye
class Foo:
    def __init__(self, s: set = set()):
        self.s = s


if __name__ == "__main__":
    f1 = Foo()
    f2 = Foo()
    f1.s.add(1)
    f1.s.add(2)
    f1.s.add(3)
    print(f2.s)

版本 3.10.4

结果会是什么呢?

7119 次点击
所在节点    Python
71 条回复
Symo
2022-08-30 16:46:59 +08:00
应该说是一个反直觉的设计缺陷.
rev1si0n
2022-08-30 16:53:00 +08:00
不是 Bug 也不是 Feature
littlewing
2022-08-30 16:53:35 +08:00
所以说 py 垃圾语言啊
yazinnnn
2022-08-30 17:04:44 +08:00
不会 python, 试了试可以这样写

class Foo:
def __init__(self, createSet = lambda : set()):
self.s = createSet()

有点反直觉, 但是想了想又算合理
Leviathann
2022-08-30 17:08:35 +08:00
彻底的设计缺陷
和 js 的 var 和 this 有得一比 甚至更恶劣
wenhaoy
2022-08-30 17:09:02 +08:00
为什么操作 f1 ,会改变 f2 的值?
hhhhhh123
2022-08-30 17:14:24 +08:00
print(id(f1), id(f2))
print(id(f1.s), id(f2.s))

140294972551120 140294972551024
140295241401280 140295241401280

破案了。
ipwx
2022-08-30 17:15:16 +08:00
不是 Bug 也不是 Feature 。我觉得有过 C++ 经验的程序员更容易接受这个设定。
sillydaddy
2022-08-30 17:17:15 +08:00
@ipwx
为啥 C++要躺枪。这明显是一个坑,C++有这么坑吗?
hhhhhh123
2022-08-30 17:18:02 +08:00
我想起来了, 这不是你们说的 设计问题, 这特么是写法问题:
如 def aaa(list =[] ) 多个使用的时候 地址同一个 所以一般参数不写空 数组 集合等。

好吧也可以说是设计问题, 但是 注意规范就行。 这特么是我老旧以前的一个面试题。。呜呜呜
ipwx
2022-08-30 17:22:11 +08:00
@sillydaddy ummm 本来觉得 C++ 也应该是类似 Python 的行为,没想到不是。

https://ideone.com/iulg3B

这还挺让我意外的。这么说来 C++ 的默认值是求值表达式,在调用时会展开。
ipwx
2022-08-30 17:23:25 +08:00
@sillydaddy 嘛不管怎么说我从内心最基本的原则里面其实早就接受了 Python 的这个行为。如果不是今天看到这个帖子你的回复我估计从来都不会发现这件事。

不过哪怕避开这种写法,C++ 写起来也应该很方便。。。至少我上面这个例子里面的用法肯定不是正常的 C++ 用法就对了。
SmiteChow
2022-08-30 17:23:54 +08:00
算 bug ,因为人们已经用工具来避免这种情况发生了。
ipwx
2022-08-30 17:24:13 +08:00
yysy 我觉得接受这种行为去写程序也没啥不好,写起来基本不会有啥不方便的。把对象构造从默认值上面移开其实是一种很好的习惯。
Eureka0
2022-08-30 17:26:45 +08:00
确实有点反直觉,但也不能说是 bug 了,别拿可变对象作为函数默认值就是了
h404bi
2022-08-30 17:34:50 +08:00
习惯 JavaScript 类似默参写法再去写 Python 特别容易中招。只能说此梨非彼梨。
ipwx
2022-08-30 17:38:33 +08:00
@h404bi 怎么说呢,其实我内心觉得任何语言在默认值里面构造堆对象都不是好的行为。

@sillydaddy 我第一反应 C++ 程序员应该不会意外这种设计,主要是 C++ 有栈对象。如果是栈对象作为默认值,那么我理所当然地认为这里栈对象本身是默认值的一个拷贝。反而如果默认值是 new XXX(),我理所当然地觉得,那这种东西作为默认值,本来就不行,涉嫌内存泄露。

简而言之就是我潜意识觉得符合 RAII 原则的程序就不会在默认值 new XXX()。毕竟连 std::shared_ptr<XXX>(new XXX) 都是错误用法,应该使用 std::make_shared<XXX>() 不是吗(笑
ipwx
2022-08-30 17:39:31 +08:00
接上一条。总之 C++ 里面我第一反应就是写个重载,然后重载函数构造一个局部栈对象或者智能指针传给参数多的那一个,根本不会轮到 new XXX 这种默认值出场。
tairan2006
2022-08-30 17:42:08 +08:00
默认形参不能用集合,我记得刚学 Python 的时候就知道了……
HashV2
2022-08-30 17:43:27 +08:00
把默认值赋值逻辑写倒方法里 不要写在参数上

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

https://www.v2ex.com/t/876494

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

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

© 2021 V2EX