1. 賦值語句的特點
- 賦值語句創建對象的引用:賦值語句總是創建對象的引用,而不是復制對象。因此,Python中的變量更像是指針,而不是數據儲存區域。
- 變量在首次賦值時會被創建:因此不需要提前聲明變量。
- 變量在引用前必須先賦值:如果引用未賦值的變量會報錯
2. 賦值語句的形式
1. 普通形式
>>> a = 'abc' # 普通形式
>>> b = 123
>>> c = [1, 2, 3]
2. 序列賦值
python中"="的右側可以接受任意類型的序列,也可以是可迭代的對象,只要長度等於左側序列即可。
>>> (a, b) = ('1', '2') # 元組賦值,括號可省略
>>> [a, b] = ['1', '2'] # 列表賦值
>>> a, b, c, d = 'spam' # 字符串序列賦值
# python中交換兩個變量的值可以不用穿件第三個臨時變量
>>> x, y = 1, 2
>>> x, y = y, x
>>> x, y
(2, 1)
# 當等號左側與右側變量長度不一致時,考慮用分片解決
>>> num = '123'
>>> a, b = num[:1], num[1:]
>>> a, b
('1', '23')
>>> num = '123'
>>> a, b = list(num[:1]) + [num[1:]]
>>> a, b
('1', '23')
# 嵌套賦值
>>> ((a, b), c) = ('12','3')
>>> a, b, c
('1', '2', '3')
3.擴展序列解包(*)
*X
:序列賦值時,帶有*的名稱會被賦值一個列表,該列表收集序列中剩下的沒被賦值給其他名稱的所有項,可用於=
左右兩側變量數目不同的情況。
>>> num = [1, 2, 3, 4]
>>> a, b = num # 變量個數不同會報錯
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
>>> a, *b = num # 擴展序列解包
>>> a, b
(1, [2, 3, 4])
>>> first, *mid, last = num # 擴展序列解包的*可以出現在任何位置
>>> first, mid, last
(1, [2, 3], 4)
邊界情況(特殊情況)
1. 帶星號的名稱值匹配到單個項,但仍然返回一個列表
>>> a = [1, 2, 3, 4]
>>> b, c, d, *e = a
>>> (b, c, d, e)
(1, 2, 3, [4])
2. 若帶星號的名稱不能匹配到任何項,則返回一個空列表
>>> a = [1, 2, 3, 4]
>>> b, c, d, e, *f = a
>>> (b, c, d, e, f)
(1, 2, 3, 4, [])
3. 若用了多個帶星號的名稱則會報錯
>>> a = [1, 2, 3, 4]
>>> *b, c, *d = a
File "<stdin>", line 1
SyntaxError: two starred expressions in assignment
4. 帶星號的名稱沒有被編寫到一個列表中會報錯
>>> a = [1, 2, 3, 4]
>>> *b = a
File "<stdin>", line 1
SyntaxError: starred assignment target must be in a list or tuple
>>> *b, = a
>>> b
[1, 2, 3, 4]
4. 多目標賦值(連續賦值)
多目標賦值即將最右側的對象依次賦值給左側所有的名稱。
>>> a = b = c = 0
>>> (a, b, c)
(0, 0, 0)
多目標賦值的共享引用問題
多目標賦值其實是多個目標對同一個內存空間的引用,這里要分兩種情況,當被引用對象是不可變對象時則不存在問題;但是如果多目標都引用了同一個可變對象,則會出現問題
>>> a = b = 1
>>> (a, b)
(1, 1)
>>> b = 2
>>> (a, b)
(1, 2)
# a的值沒有因為b的改變而改變
>>> a = b = [1, 2]
>>> (a, b)
([1, 2], [1, 2])
>>> b[1] = 3
>>> (a, b)
([1, 3], [1, 3])
# a的值隨着b值得改變而改變,即使沒有主動給a賦值,這是因為a,b同時引用了一個可變對象,改變該對象則會通知改變a和b的值