下面是Python字符串的一些微妙的特性,绝对会让你大吃一惊。python
案例一:学习
>>> a = "some_string" >>> id(a) 140420665652016 >>> id("some" + "_" + "string") # 注意两个的id值是相同的. 140420665652016
案例二:优化
>>> a = "wtf" >>> b = "wtf" >>> a is b True >>> a = "wtf!" >>> b = "wtf!" >>> a is b False >>> a, b = "wtf!", "wtf!" >>> a is b True # 3.7 版本返回结果为 False.
案例三:spa
>>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa' True >>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa' False # 3.7 版本返回结果为 True #在学习Python的过程当中,每每由于没有资料或者没人指导从而致使本身不想学下去了,所以我特地准备了个群 592539176 ,群里有大量的PDF书籍、教程都给你们无偿使用!无论是学习到哪一个阶段的小伙伴均可以获取到本身相对应的资料!
很好理解, 对吧?code
这些行为是因为 Cpython 在编译优化时, 某些状况下会尝试使用已经存在的不可变对象而不是每次都建立一个新对象. (这种行为被称做字符串的驻留[string interning])对象
发生驻留以后, 许多变量可能指向内存中的相同字符串对象. (从而节省内存)blog
在上面的代码中, 字符串是隐式驻留的. 什么时候发生隐式驻留则取决于具体的实现. 这里有一些方法能够用来猜想字符串是否会被驻留:教程
全部长度为 0 和长度为 1 的字符串都被驻留.ip
字符串在编译时被实现 ('wtf'
将被驻留, 可是 ''.join(['w', 't', 'f'])
将不会被驻留)内存
字符串中只包含字母,数字或下划线时将会驻留. 因此 'wtf!'
因为包含 !
而未被驻留. 能够在【地址1】找到 CPython 对此规则的实现.
当在同一行将 a
和 b
的值设置为 "wtf!"
的时候, Python 解释器会建立一个新对象, 而后同时引用第二个变量(译: 仅适用于3.7如下, 详细状况请看【地址2】). 若是你在不一样的行上进行赋值操做, 它就不会“知道”已经有一个 wtf!
对象 (由于 "wtf!"
不是按照上面提到的方式被隐式驻留的). 它是一种编译器优化, 特别适用于交互式环境.
常量折叠(constant folding) 是 Python 中的一种 窥孔优化(peephole optimization) 技术. 这意味着在编译时表达式 'a'*20
会被替换为 'aaaaaaaaaaaaaaaaaaaa'
以减小运行时的时钟周期. 只有长度小于 20 的字符串才会发生常量折叠. (为啥? 想象一下因为表达式 'a'*10**10
而生成的 .pyc
文件的大小). 相关的源码实如今【地址3】.
若是你是使用 3.7 版本中运行上述示例代码, 会发现部分代码的运行结果与注释说明相同. 这是由于在 3.7 版本中, 常量折叠已经从窥孔优化器迁移至新的 AST 优化器, 后者能够以更高的一致性来执行优化. (由 Eugene Toder 和 INADA Naoki 在 bpo-29469 和 bpo-11549 中贡献.)
(译: 可是在最新的 3.8 版本中, 结果又变回去了. 虽然 3.8 版本和 3.7 版本同样, 都是使用 AST 优化器. 目前不肯定官方对 3.8 版本的 AST 作了什么调整.