Python 常见的坑汇总
1. 列表与 * 操作
Python
中,*
操作符与 list
结合使用,实现元素复制。
复制 5 个空列表:
In [1]: [[]] * 5
Out[1]: [[], [], [], [], []]In [2]: a = [[]] * 5In [3]: a
Out[3]: [[], [], [], [], []]In [4]:
填充两个元素:
In [4]: a[0].extend([1,2,3])In [5]: a[1].extend([4,5,6])
期望应该为:
[[1,3,5],[2,4,6],[],[]]
实际为:
In [6]: a
Out[6]:
[[1, 2, 3, 4, 5, 6],[1, 2, 3, 4, 5, 6],[1, 2, 3, 4, 5, 6],[1, 2, 3, 4, 5, 6],[1, 2, 3, 4, 5, 6]]
原来 *
操作复制出的 a[0]
、a[1]
、...
、a[5]
,在内存中标识符是相等的,实现的仅仅是浅复制。
In [7]: id(a[0])
Out[7]: 1641831703560In [8]: id(a[1])
Out[8]: 1641831703560In [9]: id(a[2])
Out[9]: 1641831703560In [10]: id(a[3])
Out[10]: 1641831703560
在这种场景下,希望实现 id[0]
、 id[1]
不相等,修改 a[1]
不会影响 a[0]
。
不使用 *
,使用列表生成式,复制出 5 个不同 id
的内嵌列表,这样就能避免赋值互不干扰的问题。
In [12]: b = [[] for _ in range(5)]In [13]: b
Out[13]: [[], [], [], [], []]In [14]: id(b[0])
Out[14]: 1641875609928In [15]: id(b[1])
Out[15]: 1641875595080In [16]: id(b[2])
Out[16]: 1641875822344In [17]: b[0].extend([1,2,3])In [18]: b[1].extend([4,5,6])In [19]: b
Out[19]: [[1, 2, 3], [4, 5, 6], [], [], []]In [20]:
2. 删除列表元素
假设列表有重复元素,要删除列表中指定的元素,看下面代码:
In [20]: def del_list(a, x):...: for i in a:...: if i == x:...: a.remove(i)...: return a...: In [21]: a = [1,2,3,2,4]In [22]: del_list(a, 2)
Out[22]: [1, 3, 4]In [23]: del_list([1,2,3,4,3,4,3], 2)
Out[23]: [1, 3, 4, 3, 4, 3]In [24]: del_list([1,2,3,4,3,4,3], 3)
Out[24]: [1, 2, 4, 4]In [25]: del_list([1,3,5,3,2], 3)
Out[25]: [1, 5, 2]
可以看到上面的删除都是正确的,再来看下面的代码
In [26]: del_list([1,3,3,3,3,5], 3)
Out[26]: [1, 3, 3, 5]
可以看出,删除结果仍然是包含 3 , 为什么呢?
遍历列表 a
、 remove
一次,移掉位置 i
后的所有元素索引都要减一。所以,一旦删除的元素,重复出现在列表中,就总会漏掉一个该删除的元素。
正确做法,找到被删除元素后,删除,同时下次遍历索引不加一;若未找到,遍历索引加一。
一般来讲,尽量避免在列表迭代的过程中对列表进行删除、更新操作。
3. 函数默认参数为空
Python
函数的参数可设为默认值。如果一个默认参数类型为 list
,默认值为设置为 []
。
有下面函数:
In [27]: def add_list(value, volume=[]):...: if volume is None:...: volume = []...: length = len(volume)...: for i in range(length):...: volumn[i] = i + value...: return volume...:
调用 add_list
函数, val
值为 10, volume
默认值,函数返回 ret
为空列表。
In [28]: ret = add_list(10)In [29]: ret
Out[29]: []In [30]:
然后,我们向空列表 ret
中,分别添加值 1、2,打印 ret
,结果符合预期
In [30]: ret.append(1)In [31]: ret.append(2)In [32]: ret
Out[32]: [1, 2]
同样方法,再次调用 add_list
函数,第二个参数还是取默认值。预期返回值 ret
还是空列表,但是结果却出人意料!
In [41]: ret = add_list(10)In [42]: ret
Out[42]: [10, 11]
为什么返回值为 [10,11] 呢? 按照出现的结果,我们猜测 [1, 2] + 10 后,不正是 [11,12]。
原来调用函数 add_list
时,默认参数 volume
取值为默认值时,并且 volume
作为函数的返回值。再在函数外面做一些操作,再次按照默认值调用,并返回。整个过程,默认参数 volume
的 id
始终未变。
通过增加打印我们可以看到,确实是默认参数 volume
的 id
始终未变。
In [45]: ret = add_list(10)
volume id is 1641863237000In [46]: ret.append(1)In [47]: ret.append(2)In [48]: ret
Out[48]: [1, 2]In [49]: ret = add_list(10)
volume id is 1641863237000In [50]: ret
Out[50]: [10, 11]
为了避免这个隐藏的坑,函数的默认参数值切记不能设置为 []
,而是为 None
。这样即便按照默认值调用多次,也会规避此风险。
In [53]: def add_list(value, volume=None):...: print("volume id is {}".format(id(volume)))...: if volume is None:...: volume = []...: length = len(volume)...: for i in range(length):...: volume[i] = i + value...: return volume...: In [58]: ret = add_list(10)
volume id is 1929553104In [59]: ret
Out[59]: []In [60]: ret.append(1)In [61]: ret.append(2)In [62]: ret
Out[62]: [1, 2]In [63]: ret = add_list(10)
volume id is 1929553104In [64]: ret
Out[64]: []
4. {} 和 ()
单个元素要被识别为元组,必须在括号后面加个逗号 ,
详见如下代码:
In [65]: a = (10)In [66]: type(a)
Out[66]: intIn [67]: b = (10,)In [68]: type(b)
Out[68]: tuple
创建集合与字典,它们都用一对 {}
,但是默认返回字典,而不是集合。要想创建空集合,可使用内置函数 set()
In [69]: d = {}In [70]: type(d)
Out[70]: dictIn [71]: s = set()In [72]: type(s)
Out[72]: set
5. 多值赋值顺序
多值赋值是先计算出等号右侧的所有变量值后,再赋值给等号左侧变量。
In [73]: a, b = 1, 2In [74]: a, b = b+1, a+b In [75]: a, b
Out[75]: (3, 3)
Python 常见的坑汇总相关推荐
- Pytorch常见的坑汇总
来自 | 知乎 作者 | 郁振波 地址 | https://zhuanlan.zhihu.com/p/7792356 编辑 | 深度学习这件小事公众号 本文仅作学术分享,如有侵权,请联系删除 最近 ...
- Python常见web框架汇总
目前,有非常多的Python框架,用来帮助你更轻松的创建web应用.这些框架把相应的模块组织起来,使得构建应用的时候可以更快捷,也不用去关注一些细节(例如socket和协议),所以需要的都在框架里了. ...
- Python常见问题解决办法汇总
1.(unicode error) 'unicodeescape' codec can't decode bytes in position 2-3: truncated \UXXXXXXXX esc ...
- python替代hadoop_Python连接Hadoop数据中遇到的各种坑(汇总)
最近准备使用Python+Hadoop+Pandas进行一些深度的分析与机器学习相关工作.(当然随着学习过程的进展,现在准备使用Python+Spark+Hadoop这样一套体系来搭建后续的工作环境) ...
- python字符串find函数-python常见字符串处理函数与用法汇总
本文实例讲述了python常见字符串处理函数与用法.分享给大家供大家参考,具体如下: 1.find 作用:在一个较长字符串中查找子串.返回子串所在位置的最左端索引,如果没有找到则返回-1.如果指定 b ...
- js字符串replace替换多个_汇总几大python常见字符串处理函数与用法(建议收藏)...
前言: 这篇文章主要介绍了python常见字符串处理函数与用法,结合实例形式详细分析了Python字符串操作函数find.join.replace及split功能.使用技巧与操作注意事项,需要的朋友可 ...
- python代码大全下载-最全Python算法实现资源汇总!
原标题:最全Python算法实现资源汇总! 整理 | Rachel 责编 | Jane 出品 | Python大本营(ID:pythonnews) [导语]数据结构与算法是所有人都要学习的基础课程,自 ...
- python常用代码入门-最全Python算法实现资源汇总!
原标题:最全Python算法实现资源汇总! 整理 | Rachel 责编 | Jane 出品 | Python大本营(ID:pythonnews) [导语]数据结构与算法是所有人都要学习的基础课程,自 ...
- python编程入门与案例详解-quot;Python小屋”免费资源汇总(截至2018年11月28日)...
原标题:"Python小屋"免费资源汇总(截至2018年11月28日) 为方便广大Python爱好者查阅和学习,特整理汇总微信公众号"Python小屋"开通29 ...
最新文章
- 领计算机二级证材料,计算机二级证书怎么领
- 破解百度网盘的Pandownload开发者被捕,让人唏嘘
- Python高性能HTTP客户端库requests的使用
- 5.1 API : SVC
- POI设置单元格颜色及枚举颜色对照
- php 安装scws,SCWS分词扩展在windows下的安装方法
- 如何用java线程池做分批次查询处理 java线程池ThreadPoolExecutor的使用
- 前端架构设计第四课 Babel构建公共库实战
- 操作系统 银行家算法 安全性检查
- maven profile <filtering>true</filtering>的作用
- Deferred Decal
- latex 两个表格并排放置
- 重塑汽车的最新5G标准
- 使用 pip 快速安装 OpenCV
- 使用HTTPie测试Web服务
- 使用selenium操控浏览器爬取QQ音乐
- 5G时代下,射频器件、PCB等电子元器件产业面临的机遇与挑战
- 字节跳动面试凉经(挂三面)
- HTML5 全屏 API
- Android source code gerrit