(给Python开发者加星标,提升Python技能)

英文:Satwik Kansal,翻译:暮晨

Python开发者整理自 GitHub

【导读】:Python 是一个设计优美的解释型高级语言,它提供了很多能让程序员感到舒适的功能特性。但有的时候 Python 的一些输出结果对于初学者来说似乎并不是那么一目了然。

GitHub 有个仓库收集 Python 中那些难以理解和鲜为人知的功能特性,并尝试讨论这些现象背后真正的原理!

虽然有些例子并不一定会让你觉得“卧槽”(WTF),但它们依然有可能会告诉你一些你所不知道的 Python 有趣特性。我觉得这是一种学习编程语言内部原理的好办法,而且我相信你也会从中获得乐趣!

如果你是一位经验比较丰富的 Python 程序员,你可以尝试挑战看是否能一次就找到例子的正确答案。你可能对其中的一些例子已经比较熟悉了,那这也许能唤起你当年踩这些坑时的甜蜜回忆。

示例程序基于Python3.5.2。

出人意料的is!

下面是一个在互联网上非常有名的例子.

>>> a = 256
>>> b = 256
>>> a is b
True

>>> a = 257
>>> b = 257
>>> a is b
False

>>> a = 257; b = 257
>>> a is b
True

>>> a = 256
>>> b = 256
>>> a is b
True

>>> a = 257
>>> b = 257
>>> a is b
False

>>> a = 257; b = 257
>>> a is b
True
说明:

is== 的区别

  • is 运算符检查两个运算对象是否引用自同一对象 (即, 它检查两个运算对象是否相同).
  • == 运算符比较两个运算对象的值是否相等.
  • 因此 is 代表引用相同, == 代表值相等. 下面的例子可以很好的说明这点,
>>> [] == []
True
>>> [] is [] # 这两个空列表位于不同的内存地址.
False

>>> [] == []
True
>>> [] is [] # 这两个空列表位于不同的内存地址.
False

256 是一个已经存在的对象, 而 257 不是

当你启动Python 的时候, 数值为 -5256 的对象就已经被分配好了. 这些数字因为经常被使用, 所以会被提前准备好.

Python 通过这种创建小整数池的方式来避免小整数频繁的申请和销毁内存空间.

引用自 https://docs.python.org/3/c-api/long.html

当前的实现为-5到256之间的所有整数保留一个整数对象数组, 当你创建了一个该范围内的整数时, 你只需要返回现有对象的引用. 所以改变1的值是有可能的. 我怀疑这种行为在Python中是未定义行为. :-)

>>> id(256)
10922528
>>> a = 256
>>> b = 256
>>> id(a)
10922528
>>> id(b)
10922528
>>> id(257)
140084850247312
>>> x = 257
>>> y = 257
>>> id(x)
140084850247440
>>> id(y)
140084850247344

>>> id(256)
10922528
>>> a = 256
>>> b = 256
>>> id(a)
10922528
>>> id(b)
10922528
>>> id(257)
140084850247312
>>> x = 257
>>> y = 257
>>> id(x)
140084850247440
>>> id(y)
140084850247344

这里解释器并没有智能到能在执行 y = 257 时意识到我们已经创建了一个整数 257, 所以它在内存中又新建了另一个对象.

ab 在同一行中使用相同的值初始化时,会指向同一个对象.

>>> a, b = 257, 257
>>> id(a)
140640774013296
>>> id(b)
140640774013296
>>> a = 257
>>> b = 257
>>> id(a)
140640774013392
>>> id(b)
140640774013488

>>> a, b = 257, 257
>>> id(a)
140640774013296
>>> id(b)
140640774013296
>>> a = 257
>>> b = 257
>>> id(a)
140640774013392
>>> id(b)
140640774013488
  • 当 a 和 b 在同一行中被设置为 257 时, Python 解释器会创建一个新对象, 然后同时引用第二个变量. 如果你在不同的行上进行, 它就不会 "知道" 已经存在一个 257 对象了.
  • 这是一种特别为交互式环境做的编译器优化. 当你在实时解释器中输入两行的时候, 他们会单独编译, 因此也会单独进行优化. 如果你在 .py 文件中尝试这个例子, 则不会看到相同的行为, 因为文件是一次性编译的.


- EOF -