欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Learning Python Part II 之 赋值语句(Assignments)

程序员文章站 2022-06-21 18:22:33
...

特性

赋值语句创建的是对象引用

Python创建的是指向对象的引用而不是对象的拷贝。Python中的变量更像是指针而不是数据存储区域。

变量名在第一次赋值时被创建
变量在第一次被引用之前必须被赋值
一些运算隐含性的包含赋值

赋值语句不止有 = ,模块引用、函数和类定义、for循环变量、函数的参数都是隐含性的赋值,因为所有的这些操作都是将名字和对象的引用捆绑起来。

赋值语句格式

Learning Python Part II 之 赋值语句(Assignments)

序列赋值

>>> nudge = 1   #基本赋值语句
>>> wink = 2
>>> A, B = nudge, wink  #元组赋值语句
>>> A, B
(1, 2)
>>> [C, D] = [nudge, wink]  #列表赋值语句
>>> C, D
(1, 2)

在元组赋值语句中,当语句运行的时候,Python会创建一个临时的元组储存右边变量的原始值,因此我们可以不用创建临时变量来交换两个变量的值,因为右侧的元组会自动记录变量之前的值

>>> nudge = 1
>>> wink = 2
>>> nudge, wink = wink, nudge
>>> nudge, wink
(2, 1)

赋值语句两侧支持任何长度相同的序列赋值。

>>> [a, b, c] = (1, 2, 3)
>>> a, c
(1, 3)
>>> (a, b, c) = "ABC"
>>> a, c
('A', 'C')

实际上,序列赋值语句右侧支持任何可迭代的对象,不仅仅是序列。

高级用法

两侧元素数量必须相等

>>> string = 'SPAM'
>>> a, b, c, d = string
>>> a, d
('S', 'M')
>>> a, b, c = string
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 3)

可以切片赋值:

>>> a, b, c = string[0], string[1], string[2:]
>>> a, b, c
('S', 'P', 'AM')
>>> a, b, c = list(string[:2]) + [string[2:]]
>>> a, b, c
('S', 'P', 'AM')
>>> (a, b), c = string[:2], string[2:]  #嵌套序列赋值
>>> a, b, c
('S', 'P', 'AM')

for循环和函数定义中的例子:

for (a, b, c) in [(1, 2, 3), (4, 5, 6)]: ... 
for ((a, b), c) in [((1, 2), 3), ((4, 5), 6)]: ...
def f(((a, b), c)): ...
f(((1, 2), 3))

序列赋值的延伸(python3.X)

这种赋值方法只是一种方便,我们可以切片赋值达到同样的效果,但是相比较而言可以码更少的代码,少做额外工作。

>>> seq = [1, 2, 3, 4]
>>> a, *b = seq
>>> a, b
(1, [2, 3, 4])
>>> *a, b = seq
>>> a, b
([1, 2, 3], 4)
>>> a, *b, c = seq
>>> a, b, c
(1, [2, 3], 4)
>>> a, b, *c = seq
>>> a, b, c
(1, 2, [3, 4])

同样,适用于任何序列类型(实际上是任何可迭代对象):

>>> a, *b = 'spam'
>>> a, b
('s', ['p', 'a', 'm'])
>>> a, *b, c = 'spam'
>>> a, b, c
('s', ['p', 'a'], 'm')
>>> a, *b, c = range(4)
>>> a, b, c
(0, [1, 2], 3)

边界情况

星符名可能只会匹配到一个字母,但仍会被赋值一个列表:

>>> seq = [1, 2, 3, 4]
>>> a, b, c, *d = seq
>>> print(a, b, c, d)
1 2 3 [4]

当无值分配时,会被赋值一个空列表,而不是报错,并且星标名不会优先考虑:

>>> a, b, c, d, *e = seq
>>> print(a, b, c, d, e)
1 2 3 4 []
>>> a, b, *e, c, d = seq
>>> print(a, b, c, d, e)
1 2 3 4 []

有不止一个星标名、有太少常规名或只有一个星标名时没放在序列中,都会抛出错误:

>>> a, *b, c, *d = seq
SyntaxError: two starred expressions in assignment
>>> a, b = seq
ValueError: too many values to unpack (expected 2)
>>> *a = seq
SyntaxError: starred assignment target must be in a list or tuple
>>> *a, = seq
>>> a
[1, 2, 3, 4]

循环中的应用

for (a, *b, c) in [(1, 2, 3, 4), (5, 6, 7, 8)]:
...
for (a, b, c) in [(1, 2, 3), (4, 5, 6)]:
...
for all in [(1, 2, 3, 4), (5, 6, 7, 8)]:
a, b, c = all[0], all[1:3], all[3]

多目标赋值

a = b = 0,多目标赋值中只有一个对象,所有变量名指向同一个对象,所以对于可变类型可不可变类型会有一些区别;
不可变类型:

>>> a = b = 0
>>> b = b + 1
>>> a, b
(0, 1)

可变类型:

>>> a = b = []
>>> b.append(42)
>>> a, b
([42], [42])

增广赋值

这是从C语言中借鉴而来

Learning Python Part II 之 赋值语句(Assignments)

>>> x = 1
>>> x += 1
>>> x 
2
>>> S = "spam"
>>> S += "SPAM"
>>> S
'spamSPAM'

我们拓展列表时有两种方法:

>>> L = [1, 2]
>>> L = L + [3, 4]
>>> L
[1, 2, 3, 4]
>>> L.extend([7, 8])
>>> L
[1, 2, 3, 4, 7, 8]

当我们使用此方法去拓展一个列表时,Python是自动调用extend方法而不是使用更慢的+

>>> L += [9, 10]
>>> L
[1, 2, 3, 4, 7, 8, 9, 10]

但是值得注意的是,对于列表来说+=并不是完等于+=——+=允许任何类型而后者不能:

>>> L += 'spam'
>>> L
['s', 'p', 'a', 'm']
>>> L = L + 'spam'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate list (not "str") to list

还有一点不同,+=是就地改变(in-place change),而+是创建一个新对象,要注意可变对象:

>>> L = [1, 2]
>>> M = L
>>> L = L + [3, 4]
>>> L, M
([1, 2, 3, 4], [1, 2])
>>> L = [1, 2]
>>> M = L
>>> L += [3, 4]
>>> L, M
([1, 2, 3, 4], [1, 2, 3, 4])