作者:王易诺,人工智能算法工程师,Python/C++ 程序员,推理/科幻小说作者。曾于高中获得全国青少年信息学奥林匹克联赛一等奖。
现已取得复旦大学计算机科学技术学士学位,以及爱丁堡大学计算机科学硕士学位,目前正于东京大学攻读信息科学博士学位。
主要研究方向包括自然语言处理、深度学习中的跨模态任务等。
What the f**k! Python!
GitHub 上有一个项目叫做 “wtfpython”,目的就是记录那些 Python 程序猿总会感到 “What the f**k!” 的瞬间。我把这个项目的地址贴在下面,然后从里面摘录几个最经典的例子出来。
https://github.com/satwikkansal/wtfpython
首先,一些关于字符串的 “基本” 操作
1
2
3
说明:
1. 这些行为是由于 Cpython 在编译优化时,某些情况下会尝试使用已经存在的不可变对象而不是每次都创建一个新对象。(这种行为被称作字符串的驻留[string interning])。
2. 发生驻留之后,许多变量可能指向内存中的相同字符串对象(从而节省内存)。
3. 在上面的代码中,字符串是隐式驻留的。何时发生隐式驻留则取决于具体的实现. 这里有一些方法可以用来猜测字符串是否会被驻留:
- 所有长度为 0 和长度为 1 的字符串都被驻留。
- 字符串在编译时被实现( 'wtf' 将被驻留,但是 ''.join(['w', 't', 'f']) 将不会被驻留)
- 字符串中只包含字母,数字或下划线时将会驻留,所以 'wtf!' 由于包含 ! 而未被驻留。
- 当在同一行将 a 和 b 的值设置为 "wtf!" 的时候,Python 解释器会创建一个新对象,然后同时引用第二个变量(译:仅适用于3.7以下,详细情况请看这里)。如果你在不同的行上进行赋值操作,它就不会“知道”已经有一个 wtf!对象 (因为 "wtf!" 不是按照上面提到的方式被隐式驻留的)。它是一种编译器优化,特别适用于交互式环境。
- 常量折叠(constant folding) 是 Python 中的一种窥孔优化( peephole optimization)技术。这意味着在编译时表达式 'a'*20 会被替换为 'aaaaaaaaaaaaaaaaaaaa' 以减少运行时的时钟周期,只有长度小于 20 的字符串才会发生常量折叠。
关于函数的返回值——
输出:
说明:
- 当在 "try...finally" 语句的 try 中执行 return, break 或 continue 后, finally 子句依然会执行。
- 函数的返回值由最后执行的 return 语句决定。由于 finally 子句一定会执行,所以 finally 子句中的 return 将始终是最后执行的语句。
关于类的本质
输出:
说明:
- 当调用 id 函数时,Python 创建了一个 WTF 类的对象并传给 id 函数. 然后 id 函数获取其 id 值(也就是内存地址),然后丢弃该对象,该对象就被销毁了。
- 当我们连续两次进行这个操作时,Python 会将相同的内存地址分配给第二个对象。因为(在 CPython 中)id 函数使用对象的内存地址作为对象的 id 值,所以两个对象的 id 值是相同的。
- 综上,对象的 id 值仅仅在对象的生命周期内唯一。在对象被销毁之后,或被创建之前,其他对象可以具有相同的 id 值。
- 那为什么 is 操作的结果为 False 呢? 这是由对象销毁的顺序造成的.
你了解 Python 中的 for 循环语句吗 ——
输出:
说明:
由于循环在 Python 中工作方式,赋值语句 i = 10 并不会影响迭代循环,在每次迭代开始之前,迭代器(这里指 range(4) ) 生成的下一个元素就被解包并赋值给目标列表的变量(这里指 i)了
“is” 究竟是什么 ——
说明:
is 和 == 的区别
- is 运算符检查两个运算对象是否引用自同一对象(即,它检查两个运算对象是否相同)。
- == 运算符比较两个运算对象的值是否相等.
- 因此 is 代表引用相同,== 代表值相等,还有一个例子可以用来说明这一点——
256 是一个已经存在的对象,而 257 不是
当你启动 Python 的时候,数值为 -5 到 256 的对象就已经被分配好了,这些数字因为经常被使用,所以会被提前准备好。
Python 通过这种创建小整数池的方式来避免小整数频繁的申请和销毁内存空间。
is not … is not is (not …) 你在说绕口令吗?
说明:
- is not 是个单独的二元运算符,与分别使用 is 和 not 不同.
- 如果操作符两侧的变量指向同一个对象,则 is not 的结果为 False,否则结果为 True。
三个引号——
说明:
Python 提供隐式的字符串连接,例如:
' ' ' 和 " " " 在 Python中也是字符串定界符,Python 解释器在先遇到三个引号的的时候会尝试再寻找三个终止引号作为定界符,如果不存在则会导致 SyntaxError 异常。
假作真时真亦假——
输出:
说明:
- 最初,Python 并没有 bool 型 (人们用0表示假值,用非零值比如1作为真值). 后来他们添加了 True , False 和 bool 型,但是,为了向后兼容,他们没法把 True 和 False 设置为常量,只是设置成了内置变量.
- Python 3 由于不再需要向后兼容,终于可以修复这个问题了,所以这个例子无法在 Python 3.x 中执行!
骗过你的眼睛 ——
说明:
一些非西方字符虽然看起来和英语字母相同,但会被解释器识别为不同的字母。
奇怪的加号 ——
1
输出
2
输出:
说明:
- a += b 并不总是与 a = a + b 表现相同, 类实现 op= 运算符的方式也许 是不同的,列表就是这样做的。
- 表达式 a = a + [5,6,7,8] 会生成一个新列表,并让 a 引用这个新列表,同时保持 b 不变。
- 表达式 a += [5,6,7,8] 实际上是使用的是 "extend" 函数,所以 a 和 b 仍然指向已被修改的同一列表。
最后,再来一条超极机密 ——
别问,自己试一试就知道了