wtfPython就是「What the f*ck Python?
」的意思,这个项目列举了一些代码片段,可能结果和你想到的是不一致的,并且作者会告诉你为什么。本来将展示最有意义的一部分:
混合Tab和空格
1 |
|
结果是10??不是应该100么?
其实这种错误的结果的原因,所有书籍和开发者都说过,就是不要混Tab和空格,源代码你可以看项目中的mixed_tabs_and_spaces.py。
字典键的隐式转换
1 |
|
这样的原因是键被隐式的转换了:
1 |
|
生成器执行时间的差异
1 |
|
这种隐式的非预期结果在实际开发中是可能出现的。原因是in的操作是在申明时求值的,而if是在运行期求值的。
在字典迭代时修改该字典
1 |
|
首先说的时候在迭代过程中是不能修改字典的长度的:
1 |
|
但是删掉一个添加一个是可以的。运行了5次才结束是因为字典会定期重新设置以便接受更多的键,但是和项目中的运行8次是不一样的。
在列表迭代时删除条目
1 |
|
其中只有list_3是正确的行为。但是为什么会出现[2, 4]的结果呢?第一次删掉了index是0的1,就剩[2, 3, 4],然后移除index 1,
就是3,剩下了[2, 4],但是现在只有2个元素,循环就结束了。
is
1 |
|
is
用来对比身份,而==
用来对比值。通常is为True,==就是True,但是反之不一定:
1 |
|
上面的例子中,-5 - 256由于太经常使用,所以设计成固定存在的对象:
1 |
|
is not … 和 is (not …)
1 |
|
其中(not None)优先执行,最后其实变成了'something' is True
循环中的函数也会输出到相同的输出
1 |
|
我之前在[Expert-Python](https://github.com/dongweiming/Expert-
Python)这个PPT中介绍过「开发陷阱,闭包变量绑定」,其实这个例子就是因为这个问题。解决方法就是把循环的变量传到some_func里面去:
1 |
|
循环中的局部变量泄露
1 |
|
在Python 2中x的值在一个循环执行之后被改变了。不过再Python 3这个问题解决了。
可变默认参数
1 |
|
在[Expert-Python](https://github.com/dongweiming/Expert-
Python)这个PPT中同样介绍过。Python是引用传递,上面例子的参数是一个列表,它所指向的对象可以被修改。通用的解决办法是在函数内判断:
1 |
|
+ 和 +=的差别
1 |
|
通常的运算过程,区别就是a = a + X 和 a += X。这是因为a = a + X
是重新创建一个对象a,而a +=
X
是在a这个list上面做extend操作。
元组赋值
1 |
|
在我们的印象里面元组是不可变的呀?其实我之前还专门写过一篇Python元组的赋值谜题讲这个问题,简单的说对list的赋值成功了,但是赋值失败了,不过由于值是引用的,所以才会出现这个执行失败实际成功的效果。
使用在范围内未定义的变量
1 |
|
这是由于在another_func中的赋值操作会把a变成一个本地变量,但是在相同范围内并没有初始化它。如果希望它能正确运行可以加global:
1 |
|
使用finally的return
1 |
|
try…finally这种写法里面,finally中的return语句永远是最后一个执行
忽略类范围的名称解析
1 |
|
这是由于类范围的名称解析被忽略了,而生成器有它自己的本地范围,而在Python3中列表解析也有自己的范围,所以x的值是5。不过,第二个例子在Python2中SomeClass.y[0]的值是17。
列表中的布尔值
1 |
|
这是由于布尔也是int的子类:
1 |
|
###
1 |
|
看起来有点懵吧,我们拆一下:
1 |
|
这样b是5,而a[5]的值是({}, 5),所以a是{5: ({}, 5)。接着看:
1 |
|
这其实是一个对自己的「自引用」,看个例子:
1 |
|
看,a[5]就是a,这可以是一个永久循环,Python用…来表示了
版权声明:本文由 董伟明 原创,未经作者授权禁止任何微信公众号和向掘金(juejin.im)转载,技术博客转载采用 保留署名-非商业性使用-禁止演绎 4.0-国际许可协议
python