Learning Python Part II 之 賦值語句(Assignments)

特性

賦值語句創建的是對象引用

Python創建的是指向對象的引用而不是對象的拷貝。Python中的變量更像是指針而不是數據存儲區域。

變量名在第一次賦值時被創建
變量在第一次被引用之前必須被賦值
一些運算隱含性的包含賦值

賦值語句不止有 = ,模塊引用、函數和類定義、for循環變量、函數的參數都是隱含性的賦值,因爲所有的這些操作都是將名字和對象的引用捆綁起來。

賦值語句格式

這裏寫圖片描述

序列賦值

>>> 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語言中借鑑而來

這裏寫圖片描述

>>> 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])
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章