提起 Python,绝大多数同学第一印象就是”简单“。
但是,Python 中也有很多有趣、微妙的事情,如果不用心去了解,很容易在开发过程中陷入误区,久久无法自拔。
下面,就介绍几个 Python 中有趣的事情。
1. 微妙的字符串
>>> a = "wtf"
>>> b = "wtf"
>>> a is b
True
>>> a = "wtf!"
>>> b = "wtf!"
>>> a is b
False
>>> a, b = "wtf!", "wtf!"
>>> a is b
True
是不是觉得很神奇?
为什么加上
!
返回就是
False
,不加则返回
True
?
为什么加上
!
并放置同一行时,又返回
True
了?
- 这些行为是由于 Cpython 在编译优化时, 某些情况下会尝试使用已经存在的不可变对象而不是每次都创建一个新对象. (这种行为被称作字符串的驻留[string interning])
- 发生驻留之后, 许多变量可能指向内存中的相同字符串对象. (从而节省内存)
- 在上面的代码中, 字符串是隐式驻留的. 何时发生隐式驻留则取决于具体的实现. 这里有一些方法可以用来猜测字符串是否会被驻留:
- 所有长度为 0 和长度为 1 的字符串都被驻留.
- 字符串在编译时被实现 (
'wtf'
将被驻留, 但是''.join(['w', 't', 'f'])
将不会被驻留) - 字符串中只包含字母,数字或下划线时将会驻留. 所以
'wtf!'
由于包含!
而未被驻留. - 当在同一行将
a
和b
的值设置为"wtf!"
的时候, Python 解释器会创建一个新对象, 然后同时引用第二个变量。如果你在不同的行上进行赋值操作, 它就不会“知道”已经有一个wtf!
对象 (因为"wtf!"
不是按照上面提到的方式被隐式驻留的). 它是一种编译器优化, 特别适用于交互式环境.
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
is
运算符检查两个运算对象是否引用自同一对象 (即, 它检查两个运算对象是否相同).==
运算符比较两个运算对象的值是否相等.- 因此
is
代表引用相同,==
代表值相等. 下面的例子可以很好的说明这点
>>> [] == []
True
>>> [] is [] # 这两个空列表位于不同的内存地址.
False
256
是一个已经存在的对象, 而 257
不是
当你启动 Python 的时候, 数值为
-5
到
256
的对象就已经被分配好了. 这些数字因为经常被使用, 所以会被提前准备好.
Python 通过这种创建小整数池的方式来避免小整数频繁的申请和销毁内存空间.
3. is not ...
不是 is (not ...)
>>> 'something' is not None
True
>>> 'something' is (not None)
False
is not
是个单独的二元运算符, 与分别使用is
和not
不同.- 如果操作符两侧的变量指向同一个对象, 则
is not
的结果为False
, 否则结果为True
.
4. 逗号
>>> def f(x, y,):
... print(x, y)
...
>>> def g(x=4, y=5,):
... print(x, y)
...
>>> def h(x, **kwargs,):
File "", line 1
def h(x, **kwargs,):
^
SyntaxError: invalid syntax
>>> def h(*args,):
File "", line 1
def h(*args,):
^
SyntaxError: invalid syntax
- 在 Python 函数的形式参数列表中, 尾随逗号并不一定是合法的.
- 在 Python 中, 参数列表部分用前置逗号定义, 部分用尾随逗号定义. 这种冲突导致逗号被夹在中间, 没有规则定义它.(译:这一句看得我也很懵逼,只能强翻了.详细解释看下面的讨论帖会一目了然.)
5. 真亦假
True = False
if True == False:
print("I've lost faith in truth!")
输出:
I've lost faith in truth!
- 最初, Python 并没有
bool
型 (人们用 0 表示假值, 用非零值比如 1 作为真值). 后来他们添加了True
,False
, 和bool
型, 但是, 为了向后兼容, 他们没法把True
和False
设置为常量, 只是设置成了内置变量. - Python 3 由于不再需要向后兼容, 终于可以修复这个问题了, 所以这个例子无法在 Python 3.x 中执行!
这里只是举了几个例子,上面的例子是从 Github 上一个非常火热的开源项目wtfpython节选的,目前该项目已经有 2.8 万 +star,受欢迎程度可见一斑。除了英文版,它还有中文版。
它收集了 Python 中各种各样奇怪且有趣的事情,感兴趣的同学可以花时间多了解一下。