神奇的字符串

2018/12/26 18:40
阅读数 0

本篇内容全文可能只需要一分钟,阅读下面的例子,如果你能够正确知道结果的话,则不需要继续阅读余下部分.

例子

1.

>>> a = "magic_python"
>>> id(a)
140420665652016
>>> id("magic" + "_" + "python")  # id 值是一样的
140420665652016 

2.

>>> a = "magic"
>>> b = "magic"
>>> a is b
True

>
>> a = "magic!"
>>> b = "magic!"
>>> a is b
False

>
>> a, b = "magic!""magic!"
>>> a is b
True

3.

>>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'
True
>>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'
False

为什么会这样呢?

  1. 这些行为是由于 Cpython 在编译优化时, 某些情况下会尝试使用已经存在的不可变对象而不是每次都创建一个新对象. 这种行为被称作字符串池化(string interning)

  2. 在被池化后, 许多变量可能指向内存中的同一个字符串对象,从而节省内存的目的

  3. 在上面的代码中, 字符串池化是隐式的. 何时发生隐式池化则取决于具体的实现. 这里有一些方法可以用来猜测字符串是否会被池化:

    1. 所有长度为 0 和长度为 1 的字符串都会被池化.

    2. 字符串在编译时被实现 (比如 'magic' 将被池化, 但是 ''.join(['m', 'a', 'g', 'i', 'c'] 将不会被池化)

    3. 字符串中只包含字母,数字或下划线时将会池化. 所以就不难理解为什么  'magic!'  没有被池化了.

  4. 当在同一行将 a 和 b 的值设置为 "magic!" 的时候, Python 解释器会创建一个新对象, 然后同时把第二个变量指向它. 如果你在不同的行上进行赋值操作, 它就不会“知道”已经有一个 magic! 对象 (因为 "magic!" 并不符合池化的要求). 这是一种编译器优化, 特别适用于交互式环境.

  5. 常量折叠(constant folding) 是 Python 中的一种 窥孔优化(peephole optimization) 技术. 这意味着在编译时表达式 'a'*20会被替换为 'aaaaaaaaaaaaaaaaaaaa' 以减少运行时的时钟周期. 只有长度小于 20 的字符串才会发生常量折叠. 很显然这种折叠不能不限制折腾,不然对于类似 'a'*10**10 这种产生的 pyc 文件大小难以控制.

参考链接

https://github.com/python/cpython/blob/3.6/Objects/codeobject.c#L19

https://en.wikipedia.org/wiki/Peephole_optimization

https://github.com/python/cpython/blob/3.6/Python/peephole.c#L288


本文分享自微信公众号 - 桃子的学习笔记(LeeTaoThinks)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部