赋值语句
赋值语句的特性:
- 赋值语句创建对象引用,而不是对象复制;
- 变量在首次赋值时会被创建,不必提前预声明变量名;
- 变量在引用前必须先赋值;
- 某些操作会瘾式地进行赋值;
赋值语句形式
运算 | 解释 |
---|---|
spam = ‘Spam’ | 基础形式 |
spam, ham = ‘yum’, ‘YUM’ | 元组赋值(基于位置) |
[spam, ham] = [‘yun’, ‘YUM’] | 列表赋值(基于位置) |
a, b, c, d = ‘spam’ | 推广的序列赋值 |
a, *b = ‘spam’ | 扩展序列解包 |
spam = ham = ‘lunch’ | 多目标赋值 |
spam += 42 | 增量赋值(等价于spam = spam + 42) |
序列赋值
>>> nudge = 1
>>> wink = 2
>>> A, B = nudge, wink
>>> A, B
(1, 2)
>>>
>>> [C, D] = [nudge, wink]
>>> C, D
(1, 2)
>>> A
1
事实上,python中原本的元组和列表赋值形式已经得到推广,从而能在右侧接受任意类型的序列,只要长度等于左侧序列即可。
>>> [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')
扩展序列解包
推广后的序列赋值让一切变得更加方便。简而言之,一个带有单个星号的名称*X,可以用在赋值目标中;
带星号的名称会被赋值一个列表,该列表收集了序列中剩下的没被赋值给其他名称的所有项。这对于上述那种将一个序列划分为其‘前面’和‘剩余’部分的常见编码模式而言,尤其有用。
扩展的解包的实际应有
>>> seq = [1, 2, 3, 4]
>>> a, b, c, d = seq
>>> print(a, b, c, d)
1 2 3 4
>>>
>>> a, *b = seq
>>> b
[2, 3, 4]
当使用一个带星号的名称时,左侧的目标数目不必等于右侧主体对象数目。实际上,带星号的名称可以出现在目标中的任何地方。
>>> *a, b = seq
>>> a
[1, 2, 3]
当带星号的名称出现在中间时,它将收集其他列出的名称之间的所有内容。
>>> a, *b, c = seq
>>> b
[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, c, d, *e = seq
>>> print(a, b, c, d, e)
1 2 3 4 []
>>> a, b, *c, d, e = seq
>>> print(a, b, c, d, e)
1 2 [] 3 4
- 最后如果使用了多个带星号的名称或是名称数目少于值序列长度,同时没有带星号的名称,亦或是带星号的名称自身没有被编写到一个列表中,都会引发错误;
>>> a, *b, c, *e = seq
File "<stdin>", line 1
SyntaxError: two starred expressions in assignment
>>>
>>> a, b = seq
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: too many values to unpack (expected 2)
>>>
>>> *a = seq
File "<stdin>", line 1
SyntaxError: starred assignment target must be in a list or tuple
>>>
>>> *a, = seq
>>> a
[1, 2, 3, 4]
for循环中的应用
>>> for (a, *b, c) in [(1, 2, 3, 4), (5, 6, 7, 8)]:
... print(a, b, c)
...
1 [2, 3] 4
5 [6, 7] 8
多目标赋值
多目标赋值是将做右侧的对象依次赋值左侧所有的名称。
>>> a = b = c ='spam'
>>> a
'spam'
>>> b
'spam'
>>> c
'spam'
上面的代码等效于下面的代码:
>>> c = 'spam'
>>> b = c
>>> a = b
多目标赋值以及共享引用
上面的代码只创建了一个对象,但是由三个变量共享,这种行为对于不可变类型而言并没有问题,对于可变对象需要特别注意;
增量赋值
增量赋值包含了一个二元表达式以及一个赋值表达式;
X += Y
X *= Y
X %= Y
X &= Y
X ^= Y
X <<= Y
X -= Y
X /= Y
X **= Y
X |= Y
X >>= Y
X //= Y
增量赋值语句有以下三个优点:
- 能够减少程序员的输入;
- 左侧只需计算一次,X可以是一个复杂的对象表达式;
- 增量赋值有着自动选择的优化技术;
变量命名规则
- 变量名只能包含字母、数字和下划线。变量名可以以字母和下划线开头,不能以数字开头
- 变量名不能包含空格,但是可以使用下划线进行字母分割
- 不能以python中的关键字和函数名做为变量
- 变量名应该简短并且具有描述性
- 慎用小写字母l和大写字母O,避免认为是数字1和0。
python3的保留字
>>> import keyword
>>> keyword.kwlist
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
命名惯例
- 以单一下划线开头的名称(_X)不会被from module import *语句导入;
- 前后均有双下划线的名称(_ X _)是系统定义的名称,对解释器有特殊意义;
- 以双下划线开头,但结尾没有双下划线的名称(__X)是外围类的本地变量;
- 通过交互式命令行运行时,只有单个下划线的名称(_)会保存最后一个表达式的结果;
表达式语句
表达式通常在以下两种情况中用作语句:
- 调用函数和方法;
- 在交互式命令行下打印值;
常见的python表达式语句
代码 | 作用 |
---|---|
spam(eggs, ham) | 函数调用 |
spam.ham(eggs) | 方法调用 |
sapm | 在交互式解释器中打印变量 |
print(a, b, c, seq=’’) | 在python3.x中打印 |
yield x**2 | yield表达式语句 |
需要注意,虽然表达式在python中可作为语句出现,但语句不能用作表达式。
打印操作
详细的说,python中的打印操作于文件和流的概念紧密相连:
- 文件对象方法;
文件写入方法是把字符串写入到任意的文件中,而print则是默认地把对象写入stdout流,同时加入了一些自动的格式化。与写入文件方法不同,打印操作不需要预先把对象转换为字符串; - 标准输出流;
print函数
print内置函数的调用通常独占一行,但它不会返回任何我们期望的值。
>>> x = print('spam')
spam
>>> print(x)
None
调用形式
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)
value, …(表达可以同时打印多个对象;)
sep= ’ '(打印的多个文件或对象的分隔;)
end(是添加在打印文本末尾的一个字符串;)
file(指定了文本将要发送到文件、标准流,或其他类似文件的对象;)
flush(强制文本通过输出流离基刷新给等待中的接受者;)