既然不可变对象是不可修改的,当我创建了两个相同的不可变对象时,为什么不复用之前已经创建好的对象?
如下,为什么 b 不复用 a 呢?这样不是可以节省内存吗?
>>> a = (1,2,3)
>>> b = (1,2,3)
>>> a is b
False
1
congeec 2018-10-11 11:02:06 +08:00 via iPhone
小对象复用啊,比如某些小整数
如果想复用,还要查一遍,花时间 |
2
hanxiaomeng OP @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 ``` |
3
EchoUtopia 2018-10-11 11:50:10 +08:00
tuple 里面可以存可变对象,比如 list,所以要复用的话稍微复杂点
|
4
glacer 2018-10-11 11:57:41 +08:00
小整数,字符串是有复用机制的,小整数直接存数组,大整数是复用内存空间减少系统 malloc。
字符串利用 dict 来进行对象复用,Python 对于用字符串做 key 的 dict 查找的方法做了很好的优化,所以对字符串都做了完整的复用。 @hanxiaomeng |
5
momocraft 2018-10-11 12:01:04 +08:00
语言级别复用这个可能需要查找表,需要极大量的内存,我不知道有语言以此作为“优化”的
(immutable.js / scala.collection 这些能复用数据结构是因为每次更新时天然知道能复用的对象在哪) |
6
whileFalse 2018-10-11 13:10:40 +08:00
主要问题是,它 TM 怎么知道 a 和 b 是同一个对象呢?一定要判断才能知道是同一个。
对于字符串来说,编译时会把所有字符串写入同一个内存区域,此时可以查重。 对于元组来说,看起来是没有做此处理。 |
7
hanxiaomeng OP @EchoUtopia 有道理,如果复用了,会导致元组中的可变对象相同。
|
8
hanxiaomeng OP @whileFalse
@momocraft @glacer @whileFalse 谢谢各位的解答。 对字符串复用我是理解的,经过 @EchoUtopia 的提醒,也理解了复合数据类型不能复用的原因。 我最主要的疑惑在于,从我所认识到的角度讲,大整数、浮点数和字符串一样,应该也可以直接复用啊,为毛 Python 只复用了小整数这一部分.... |
9
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,而应该用 ==。 |