0x00
>>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa' True >>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa' False # 2.7 版本返回 False # 3.7 版本返回结果为 True
很神奇的一个结果,第一次看到时我也惊呆了,事实上这是 Python 的一种优化机制,叫常量折叠。这意味着在编译时表达式 'a'*20
会被替换为 aaaaaaaaaaaaaaaaaaaa
以减少运行时时常,而只有长度小于 20 的字符串才会发生常量折叠。
0x01
In [3]: a = 'python' In [4]: b = 'python' In [5]: a is b Out[5]: True In [6]: x = 'python!' In [7]: y = 'python!' In [8]: x is y Out[8]: False
这是因为在编译优化时 Python 会尝试使用一些已经存在的不可辨对象,这种现象称之为字符串驻留,而只包含字母数字和下划线的字符串在编译时是会驻留的,包含 !
的字符串是不会驻留的。
0x02
In [11]: some_dict = {} In [12]: some_dict[5.5] = 'Java' In [13]: some_dict[5.0] = 'Ruby' In [14]: some_dict[5] = 'Python' In [15]: some_dict[5.5] + '_' + some_dict[5.0] + '_' + some_dict[5] Out[15]: 'Java_Python_Python' In [16]: 5 == 5.0 Out[16]: True In [17]: hash(5) == hash(5.0) Out[17]: True
Python 字典通过比较不可变对象是否相等和哈希值是否相等来确定是否为不同的键,但不同值的对象也可能具有相同的哈希值。因此字典以为 5.0 和 5 是同一个键,所以 Python 会覆盖掉 Ruby。
0x03
In [21]: def some_func(): ...: try: ...: return 'from_try' ...: finally: ...: return 'from_finally' ...: In [22]: some_func() Out[22]: 'from_finally'
函数的返回值由最后 return 的语句决定,而 finally 一定是最后之行的,所以会覆盖掉 try 中的 return 结果。
0x04
In [23]: for i in range(3): ...: print(i) ...: i = 10 ...: 0 1 2
在每次循环开始之前, 迭代器生成的下一个元素会重新赋值给 i,因此赋值语句 i = 10 并不会影响循环。