何谓坑:凡是和大多数人的直观理解不一致的,都可称之为“坑”
一部分在其他博文中提到过,不再重复
比如:
1 | 默认参数最好不为可变对象 |
博文:python进阶17炫技巧,中提过,所以不再重复
博文:python阅读wtfbook疑问和验证,也记录了一些坑,也不再重复
本文作为对以上的补充
括号和元组()
单个元素要被识别为元组,必须在括号后面加个逗号 , 详见如下代码:
1 | In [65]: a = (10) |
空集合空字典{}
创建集合与字典,它们都用一对 {},但是默认返回字典,而不是集合。要想创建空集合,可使用内置函数 set()
1 | In [69]: d = {} |
默认参数最好不为可变对象
函数的参数分三种 - 可变参数 - 默认参数 - 关键字参数
当你在传递默认参数时,有新手很容易踩雷的一个坑。
先来看一个示例
1 | def func(item, item_list=[]): |
在这里,你可以暂停一下,思考一下会输出什么?
思考过后,你的答案是否和下面的一致呢
1 | ['iphone'] |
如果是,那你可以跳过这部分内容,如果不是,请接着往下看,这里来分析一下。
Python 中的 def 语句在每次执行的时候都初始化一个函数对象,这个函数对象就是我们要调用的函数,可以把它当成一个一般的对象,只不过这个对象拥有一个可执行的方法和部分属性。
对于参数中提供了初始值的参数,由于 Python 中的函数参数传递的是对象,也可以认为是传地址,在第一次初始化 def 的时候,会先生成这个可变对象的内存地址,然后将这个默认参数 item_list 会与这个内存地址绑定。在后面的函数调用中,如果调用方指定了新的默认值,就会将原来的默认值覆盖。如果调用方没有指定新的默认值,那就会使用原来的默认值。
stackoverflow上有一个更适当的例子来说明默认参数是在定义的时候求值,而不是调用的时候。
时有时无的切片异常
alist 只有5 个元素,当你取第 6 个元素时,会抛出索引异常。这与我们的认知一致。
1 | >>> alist = [0, 1, 2, 3, 4] |
但是当你使用 alist[5:] 取一个区间时,即使 alist 并没有 第 6个元素,也不抛出异常,而是会返回一个新的列表。
1 | >>> alist = [0, 1, 2, 3, 4] |
return不一定都是函数的终点
那结论就出来了,如果 finally 里有显式的 return,那么这个 return 会直接覆盖 try 里的 return,而如果 finally 里没有 显式的 return,那么 try 里的 return 仍然有效。
用户无感知的小整数池
Python 定义了一个小整数池 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收。
循环中的局部变量泄露
python版本升级
python3.x并不向后兼容,所以如果从2.x升级到3.x的时候得小心了,下面列举两点:
在python2.7中,range的返回值是一个列表;而在python3.x中,返回的是一个range对象。
map()、filter()、 dict.items()在python2.7返回列表,而在3.x中返回迭代器。当然迭代器大多数都是比较好的选择,更加pythonic,但是也有缺点,就是只能遍历一次。在instagram的分享中,也提到因为这个导致的一个坑爹的bug。
参考
Python 黑魔法指南 50 例:python.iswbm.com/en/latest/c01/c01_10.html
Python有什么不为人知的坑?:https://www.zhihu.com/question/29823322?sort=created
这十多个Python中的坑,简直太恶心了,摔的我眼冒金星:https://www.pythonf.cn/read/42134
python实战系列
python实战02异常报错
python实战04常见坑
python实战05文件路径(找不到文件)
python实战06多线程bug处理记录
python实战07调试pdb
python实战08多线程性能分析(装饰器和chromeTrace)
python实战10pytest测试和覆盖率