Python学习笔记——序列赋值

Python学习笔记——序列赋值

Python 程序员会默认序列是支持+ 和* 操作的。通常+ 号两侧的序列由相同类型的数据所
构成,在拼接的过程中,两个被操作的序列都不会被修改,Python 会新建一个包含同样类
型数据的序列来作为拼接的结果。
如果想要把一个序列复制几份然后再拼接起来,更快捷的做法是把这个序列乘以一个整
数。同样,这个操作会产生一个新序列:

>>> l = [1, 2, 3]
>>> l * 5
[1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
>>> 5 * 'abcd'
'abcdabcdabcdabcdabcd'

+ 和* 都遵循这个规律,不修改原有的操作对象,而是构建一个全新的序列。

有时我们会需要初始化一个嵌套着几个列表的列表,譬如一个列表可能需要用来存放不同
的学生名单,或者是一个井字游戏板3 上的一行方块。想要达成这些目的,最好的选择是使
用列表推导:

>>> board = [['_'] * 3 for i in range(3)] 
>>> board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
>>> board[1][2] = 'X' 
>>> board
[['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]

另一个方法看上去是个诱人的捷径,但实际上它是错的,含有3 个指向同一对象的引用的列表是毫无用处的:

>>> weird_board = [['_'] * 3] * 3 
>>> weird_board
[['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
>>> weird_board[1][2] = 'O' 
>>> weird_board
[['_', '_', 'O'], ['_', '_', 'O'], ['_', '_', 'O']]

序列的增量赋值:
增量赋值运算符+= 和*= 的表现取决于它们的第一个操作对象。简单起见,我们把讨论集
中在增量加法(+=)上,但是这些概念对*= 和其他增量运算符来说都是一样的。
+= 背后的特殊方法是__iadd__(用于“就地加法”)。但是如果一个类没有实现这个方法的
话,Python 会退一步调用__add__。考虑下面这个简单的表达式:

>>> a += b

如果a 实现了__iadd__ 方法, 就会调用这个方法。同时对可变序列( 例如list、
bytearray 和array.array)来说,a 会就地改动,就像调用了a.extend(b) 一样。但是如
果a 没有实现__iadd__ 的话,a += b 这个表达式的效果就变得跟a = a + b 一样了:首先
计算a + b,得到一个新的对象,然后赋值给a。也就是说,在这个表达式中,变量名会不
会被关联到新的对象,完全取决于这个类型有没有实现__iadd__ 这个方法。
总体来讲,可变序列一般都实现了__iadd__ 方法,因此+= 是就地加法。而不可变序列根
本就不支持这个操作,对这个方法的实现也就无从谈起。

>>> l = [1, 2, 3]
>>> id(l)
4311953800>>> l *= 2
>>> l
[1, 2, 3, 1, 2, 3]
>>> id(l)
4311953800>>> t = (1, 2, 3)
>>> id(t)
4312681568>>> t *= 2
>>> id(t)
4301348296 ➍
➊ 刚开始时列表的ID。
➋ 运用增量乘法后,列表的ID 没变,新元素追加到列表上。
➌ 元组最开始的ID。
➍ 运用增量乘法后,新的元组被创建。

一个关于+=的谜题:

>>> t = (1, 2, [30, 40])
>>> t[2] += [50, 60]

到底会发生下面4 种情况中的哪一种?
a. t 变成(1, 2, [30, 40, 50, 60])。
b. 因为tuple 不支持对它的元素赋值,所以会抛出TypeError 异常。
c. 以上两个都不是。
d. a 和b 都是对的。

答案是d


>>> t = (1, 2, [30, 40])
>>> t[2] += [50, 60]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 40, 50, 60])

• 不要把可变对象放在元组里面。
• 增量赋值不是一个原子操作。我们刚才也看到了,它虽然抛出了异常,但还是完成了操作。

参考:流畅的Python

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值