Python学习笔记(六)—— 序列运算
来源:互联网 发布:用友软件下载 编辑:程序博客网 时间:2024/05/17 23:46
代码及内容源自《Fluent Python》——Luciano Ramalho 著
序列支持“+”和“*”运算,通常要求运算符两侧为相同的序列类型,并且运算的结果是生成一个新的序列而不会改变原来的任何一个运算对象。
>>> l=[1,2,3]>>> l*5
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> 5*'abcd'
'abcdabcdabcdabcdabcd'
有时,我们会需要用一定数量的嵌套列表来初始化一个列表。此时,最好的做法是采用list comprehension,如下
>>> board=[['_']*3 for i in range(3)]>>> board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
>>> board[1][1]='X'>>> board
[['_', '_', '_'], ['_', 'X', '_'], ['_', '_', '_']]
与之相对的一种诱人却错误的方式是
>>> weird_board=[['_']*3]*3>>> weird_board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
>>> weird_board[1][1]='Y'>>> weird_board
[['_', 'Y', '_'], ['_', 'Y', '_'], ['_', 'Y', '_']]
这段异常代码的问题在于,它的实际执行在本质上与下述代码类似:
>>> row=['_']*3>>> board=[]>>> for i in range(3):... board.append(row)
即,同一个row被引用了三次。不同的是,list comprehension的作用等同于下面的代码:
>>> board=[]>>> for i in range(3):... row=['_']*3... board.append(row)>>> board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
>>> board[1][1]='Y'>>> board
[['_', '_', '_'], ['_', 'Y', '_'], ['_', '_', '_']]
增量赋值“+=”,“*=”
增量赋值运算结果依赖于第一个运算对象,运算对象的类型不同,结果也有差别。
“+=”工作的基础是特殊方法__iadd__,如果该方法没有被实现,Python就会调用__add__。对于后者,由于运算中生成了新的对象,所以再赋值后会改变原操作对象的ID。该原理同样适用于“*=”,对应的特殊方法为__imul__。
>>> l=[1,2,3]>>> id(l)
2297732364616
>>> l*=2>>> l
[1, 2, 3, 1, 2, 3]
>>> id(l)
2297732364616
>>> t=(1,2,3)>>> id(t)
2297732591552
>>> t*=2>>> t
(1, 2, 3, 1, 2, 3)
>>> id(t)
2297732664584
下面试着根据代码来判断哪个答案是正确的:
t=(1,2,[30,40])t[2]+=[50,60]
a. t变为(1, 2, [30, 40, 50, 60])
b. TypeError: ‘tuple’ object does not support item assignment
c. a和b都不对
d. a和b都对
多数人会选择答案b,但实际上正确答案是d。以下是实际的执行结果。
>>> t=(1,2,[30,40])>>> t[2]+=[50,60]
---------------------------------------------------------------------------TypeError Traceback (most recent call last)<ipython-input-19-a113d2524452> in <module>() 1 t=(1,2,[30,40])----> 2 t[2]+=[50,60]TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60])
查看一下Python生成的字节码,能够更清楚的了解这是如何发生的。
>>> import dis>>> dis.dis('S[a]+=b')
1 0 LOAD_NAME 0 (S) 2 LOAD_NAME 1 (a) 4 DUP_TOP_TWO 6 BINARY_SUBSCR 8 LOAD_NAME 2 (b) 10 INPLACE_ADD 12 ROT_THREE 14 STORE_SUBSCR 16 LOAD_CONST 0 (None) 18 RETURN_VALUE
- “BINARY_SUBSCR” 将S[a]的值置于栈顶(Top Of Stack,TOS)
- “INPLACE_ADD” 执行增量运算TOS +=b,如果TOS是一个mutable对象,这一过程被成功执行。(上例中,它是一个列表)
- “STORE_SUBSCR” 执行赋值,S[a]=TOS, 这一过程失败,因为S是immutable对象。(上例中,t是一个tuple)
虽然这个例子所展示的情况并不常见,但是从该例中还是能学到以下几点:
- 将mutable项置于tuple中不是一个好主意。
- 增量赋值并不是一个atomic operation,正如上例中,它会在完成部分工作后,才将错误抛出。
- 检查Python的字节码并不困难,并且通常都会有很大帮助。
阅读全文
0 0
- Python学习笔记(六)—— 序列运算
- Python学习笔记(六)—Python的运算符
- Python学习笔记(六)— 函数
- OpenCV学习笔记(六)—序列
- [python]python学习笔记(六)——界面编程
- Python学习笔记(六)——Python 函数
- Objective-C学习笔记(六)——运算符之一元运算符
- Python学习(六)------- 序列类型
- Python学习笔记(六)——一些语句
- Python学习笔记(六)——面向对象编程
- Python学习笔记(六)——函数
- python学习笔记(六)
- python 学习笔记(六)
- Python学习笔记(六)
- Python学习笔记(六)
- python学习笔记(六)
- Python学习笔记(六)
- Python学习笔记(六)
- Android使用RecycleView实现魅族手机通讯录界面
- DIV+CSS首页布局练习 代码
- hdu 1548
- Hadoop集群开发
- mybatis和hibernate的区别
- Python学习笔记(六)—— 序列运算
- vc调试大全
- matplotlib.pyplot画灰度图
- 腾讯云直播~上
- Android VR Player(全景视频播放器) [5]:简单的欢迎界面
- 线性筛法(一)--素数筛法(二)
- CSS中隐藏内容的3种方法
- 带参数的main函数
- 分享一个Android 分类打印,及日志记录工具