提问:为什么 Python 不复用所有的不可变对象?

2018-10-11 10:47:44 +08:00
 hanxiaomeng

既然不可变对象是不可修改的,当我创建了两个相同的不可变对象时,为什么不复用之前已经创建好的对象?

如下,为什么 b 不复用 a 呢?这样不是可以节省内存吗?

>>> a = (1,2,3)
>>> b = (1,2,3)
>>> a is b
False
1398 次点击
所在节点    问与答
9 条回复
congeec
2018-10-11 11:02:06 +08:00
小对象复用啊,比如某些小整数

如果想复用,还要查一遍,花时间
hanxiaomeng
2018-10-11 11:21:36 +08:00
@congeec 嗯,感谢回答,从效率的角度讲确实是这样。

不过为什么对于字符串 Python 却直接复用了,是字符串与其他对象的查询效率不同吗?代码如下:
```
#Python 3.5
>>> a = '555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555'
>>> b = '555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555'
>>> a is b
True
>>> a = 1.0
>>> b = 1.0
>>> a is b
False
>>> a = 1000000000000
>>> b = 1000000000000
>>> a is b
False
```
EchoUtopia
2018-10-11 11:50:10 +08:00
tuple 里面可以存可变对象,比如 list,所以要复用的话稍微复杂点
glacer
2018-10-11 11:57:41 +08:00
小整数,字符串是有复用机制的,小整数直接存数组,大整数是复用内存空间减少系统 malloc。
字符串利用 dict 来进行对象复用,Python 对于用字符串做 key 的 dict 查找的方法做了很好的优化,所以对字符串都做了完整的复用。
@hanxiaomeng
momocraft
2018-10-11 12:01:04 +08:00
语言级别复用这个可能需要查找表,需要极大量的内存,我不知道有语言以此作为“优化”的

(immutable.js / scala.collection 这些能复用数据结构是因为每次更新时天然知道能复用的对象在哪)
whileFalse
2018-10-11 13:10:40 +08:00
主要问题是,它 TM 怎么知道 a 和 b 是同一个对象呢?一定要判断才能知道是同一个。

对于字符串来说,编译时会把所有字符串写入同一个内存区域,此时可以查重。
对于元组来说,看起来是没有做此处理。
hanxiaomeng
2018-10-11 13:14:57 +08:00
@EchoUtopia 有道理,如果复用了,会导致元组中的可变对象相同。
hanxiaomeng
2018-10-11 13:25:24 +08:00
@whileFalse
@momocraft
@glacer
@whileFalse
谢谢各位的解答。
对字符串复用我是理解的,经过 @EchoUtopia 的提醒,也理解了复合数据类型不能复用的原因。

我最主要的疑惑在于,从我所认识到的角度讲,大整数、浮点数和字符串一样,应该也可以直接复用啊,为毛 Python 只复用了小整数这一部分....
Wincer
2018-10-11 13:34:24 +08:00
首先 is 运算符是身份运算符,用于比较对象标识。即使构造了两个具有相同内容的对象,他们的标识也不应该相等,这是设计如此。
然后你举的那个字符串的例子,其实只要在字符串中加上一个空格,就会发现这两个字符也不相等了:

```
a = 'a '
b = 'a '
a is b
>>> False
```

那么不加空格为什么会相等呢?这是 CPython 的实现在存储一些小字符串时,会将这些内容分割存放,而字符串一旦长了,也会不相等:

```
a = 'a'*10000
b = 'a'*10000
a is b
>>> False
```

这属于 CPython 的实现细节,与 Python 本身无关。
但无论如何,要比较对象或者字符串相等,不应该用 is,而应该用 ==。

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

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

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

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

© 2021 V2EX