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

来源:互联网 发布:sql union横向合并 编辑:程序博客网 时间:2024/05/16 08:54

特性

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

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 = stringTraceback (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 = seqSyntaxError: two starred expressions in assignment
>>> a, b = seqValueError: too many values to unpack (expected 2)
>>> *a = seqSyntaxError: 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])
原创粉丝点击