V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
hanxiaomeng
V2EX  ›  问与答

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

  •  
  •   hanxiaomeng · 2018-10-11 10:47:44 +08:00 · 1409 次点击
    这是一个创建于 2269 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

    >>> a = (1,2,3)
    >>> b = (1,2,3)
    >>> a is b
    False
    
    9 条回复    2018-10-11 13:34:24 +08:00
    congeec
        1
    congeec  
       2018-10-11 11:02:06 +08:00 via iPhone
    小对象复用啊,比如某些小整数

    如果想复用,还要查一遍,花时间
    hanxiaomeng
        2
    hanxiaomeng  
    OP
       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
        3
    EchoUtopia  
       2018-10-11 11:50:10 +08:00
    tuple 里面可以存可变对象,比如 list,所以要复用的话稍微复杂点
    glacer
        4
    glacer  
       2018-10-11 11:57:41 +08:00
    小整数,字符串是有复用机制的,小整数直接存数组,大整数是复用内存空间减少系统 malloc。
    字符串利用 dict 来进行对象复用,Python 对于用字符串做 key 的 dict 查找的方法做了很好的优化,所以对字符串都做了完整的复用。
    @hanxiaomeng
    momocraft
        5
    momocraft  
       2018-10-11 12:01:04 +08:00
    语言级别复用这个可能需要查找表,需要极大量的内存,我不知道有语言以此作为“优化”的

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

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

    我最主要的疑惑在于,从我所认识到的角度讲,大整数、浮点数和字符串一样,应该也可以直接复用啊,为毛 Python 只复用了小整数这一部分....
    Wincer
        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,而应该用 ==。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2828 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 02:45 · PVG 10:45 · LAX 18:45 · JFK 21:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.