[python]运算符与表达式

1. 数字操作

所有数字类型可进行以下操作:

操作 描述
x + y 加法
x - y 减法
x * y 乘法
x / y 除法
x // y 截断除法
x ** y 乘方(x的y次方)
x % y 取模(x mod y)
-x 一元减法
+x 一元加法

截断除法运算符"//",也称为地板除法,把结果截取为一个整数,并且整数和浮点数均可应用。取模运算符返回的是x // y的余数,对于浮点数,取模运算符返回的是x // y的浮点余数。对于复数,取模和截断除法运算符是无效的。
以下移位和按位逻辑运算符只能应用于整数:

操作 描述
x << y 左移
x >> y 右移
x & y 按位与
x | y 按位或
x ^ y 按位异或
~x 按位求反

以下内置函数支持所有数字类型:

操作 描述
abs(x) 绝对值
divmod(x,y) 返回(x // y, x % y)
pow(x, y [, modulo]) 返回(x ** y) % module
round(x [,n]) 四舍五入为接近的10^-n的倍数(只返回浮点数)

abs()函数返回数字的绝对值。divmod()函数返回除法操作的商和余数,只对非复数有效。pow()函数可以用于代替**运算符。round()函数将一个浮点数x四舍五入为最近的10^-n的倍数,如果省略n,它将被设为0.
以下比较运算符具有标准的数学解释,返回值为布尔型的True或False:

操作 描述
x < y 小于
x > y 大于
x == y 等于
x != y 不等于
x >= y 大于等于
x <= y 小于等于

比较运算符可以连在一起,比如x < y < z。这类表达式等价于x < y and y < z。不允许对复数进行比较,否则会引发TypeError异常。只有当操作数属于同一类型时,对这些操作数进行运算才是有效的。对于内置数字,Python将进行强制类型转换,转换规则如下:
1) 如果操作数之一为复数,则将另一个操作数也转换为复数。
2) 如果操作数之一为浮点数,则将另一个操作数也转换为浮点数。
3) 否则,两个操作数必须同时为整数,不需要进行转换。

2. 序列操作

序列类型(包括字符串、列表和元组)支持的运算符如下所示:

操作 描述
s + r 连接
s n, n s 制作s的n个副本,n为整数
v1, v2..., vn = s 变量解包
s[i] 索引
s[i:j] 切片
s[i:j:stride] 扩展切片
x in s, x not in s 从属关系
for x in s: 迭代
all(s) 如果s中的所有项都为True,则返回False
any(s) 如果s中的任意项为True,则返回True
len(s) 长度
min(s) s中的最小项
max(s) s中的最大项
sum(s [, initial]) 具有可选初始值的项的和

"+"运算符用于连接相同类型的两个序列。s * n运算符制作一个序列的n个副本。但是,这些副本仅仅是浅复制。
所有序列都可以被解包为一列变量名称,例如:

items = [3, 4, 5]
x, y, z = items
datetime = ((5, 19, 2008), (10, 30, "am"))
(month, day, year), (hour, minute, am_pm) = datetime

将值解包到变量中时,变量的个数必须严格匹配序列中元素的个数。另外,变量的结构也必须匹配序列的结构。
索引运算符s[n]返回序列中的第n个对象,而s[0]是第一个对象。使用负数索引可以获取序列尾部的字符。试图访问超出边界的元素将引发IndexError异常。
切片运算符s[i:j]从s中提取一个子序列,它所包含的元素索引k的范围是i <= k < j。切片运算符支持使用负数索引,并且假定它关联到序列的结尾。
x in s运算符测试对象x是否在序列s中,返回值为True或False。类似地,x not in s 运算符测试x是否不在序列s中。对于字符串对象,in和not in运算符接受子字符串。比如:" 'hello' in 'hello world' "。需要注意的是,in运算符不支持通配符或任意类别的模式匹配。
for x in s运算符用于迭代序列的所有元素。len(s)返回序列中元素的个数。min(s)和max(s)分别返回一个序列中的最小值和最大值。sum(s)用于对s中的所有项求和,但只在其中的各项代表数字时有效。
字符串和元组是不可变的,创建后不能修改。列表可通过以下运算符进行修改:

操作 描述
s[i] = x 索引赋值
s[i:j] = r 切片赋值
s[i:j:stride] = r 切片扩展赋值
del s[i] 删除一个元素
del s[i:j] 删除一个切片
del s[i:j:stride] 删除一个扩展切片

s[i] = x运算符将列表的元素i修改为引用对象x,同时增加x的引用计数。负索引值将关联到列表结尾,试图给超出范围的索引赋值将引发IndexError异常。切片赋值运算符s[i:j] = r将使用序列r中的元素替换元素k,其中k的范围是i <= k < j。如果有必要,将对序列s进行扩展或收缩,以便容纳r中的所有元素,例如:

a = [1, 2, 3, 4, 5]
a[1] = 6 # a = [1, 6, 3, 4, 5]
a[2:4] = [10, 11] # a = [1, 6, 10, 11, 5]
a[3:4] = [-1, -2, -3] # a = [1, 6, 10, -1, -2, -3, 5]
a[2:] = [0] # a = [1, 6, 0]

切片赋值可以提供一个可选的步进参数。但这种行为受到的限制更大,右边的参数必须与要替换切片的元素个数完全相同。
del s[i]运算符从列表中删除元素i,同时减少它的引用计数。del s[i:j]删除切片内的所有元素。切片删除也可以指定步进参数。
使用运算符<、>、<=、>=、==、!=可以对序列进行比较。比较两个序列时,首先比较每个序列的第一个元素。如果它们不同,即可以得出结论。如果它们相同,就继续比较。如果a是b的子序列,那么a < b。

3. 字符串格式化

取模运算符(s % d)生成格式化的字符串,其中s是一个格式字符串,而d是一个对象元组或映射对象(字典)。格式字符串包含两类对象:普通字符和转换说明符,将使用可表示相关元组或映射中元素的格式化字符串来替换这些转换说明符。如果d是一个元组,转换说明符的个数必须与d中对象的个数保持一致。如果d是一个映射,每个转换说明符都必须与映射中的一个有效键名关联。每个转换说明符都以%开始,如下表:

字符 输出格式
d, i 十进制整数或长整数
u 无符号整数或长整数
o 八进制整数或长整数
x 十六进制整数或长整数
X 十六进制整数(大写字母)
f 浮点数,如[-]m.dddddd
e 浮点数,如[-]m.dddddd+(-)xx
E 浮点数,如[-]m.dddddd+(-)xx
g, G 指数小于-4或更高精度时使用%e或%E,否则使用%f
s 字符串或任意对象
r 同repr()生成的字符串
c 单个字符
% 字面量%

在%字符和转换字符之间,可以出现以下修饰符,并且只能按照以下顺序出现:
1) 位于括号中的一个键名,用于从映射对象中选出一个具体项。
2) -,左对齐标志。默认是右对齐。
3) +,表示应该包含数字符号。
4) 0,表示一个零填充。
5) 一个指定最小自动宽度的数字。
6) 一个小数点,用于按照精度分割字段宽度。
7) 一个数字,指定要打印字符串中的最大字符个数,浮点数中小数点之后的位数,或者整数的最小位数。
星号"*"字符用于在任意宽度的字段中替换数字。
以下代码给出一些例子:

a = 42
b = 13.142783
c = "hello"
d = {'x':13, 'y':1.54321, 'z': 'world'}
e = 5628398123741234

r = "a is %d" % a # r = "a is 42"
r = "%10d %f" % (a, b) # r = "        42  13.142783"
r = "%+010d %E" % (a, b) # r = "+0000000042 1.314278E+01"
r = "%(x)-10d %(y)0.3g" % d # r = "13        1.54"
r = "%0.4s %s" % (c, d['z']) # r = "hell world"
r = "%*.*f" % (5, 3, b) # r = "13.143"
r = "e = %d" % e # r = "e = 5628398123741234"

字符串格式化有一种更加高级的形式,即使用字符串的s.format(args, kwargs)方法。该方法收集位置参数和关键字参数的任意集合,并使用它们的值来替换s中嵌入的占位符。例如:

r = "{0} {1} {2}".format{'GOOG', 100, 490.91}
r = "{name} {shares} {price}".format{name='GOOG', shares=100, price=490.10}

如果要输出一个"{"或"}",必须使用"{{"或"}}"的形式。使用占位符还可以执行其他索引和属性查找,例如:

stock = {
    'name': 'GOOG',
    'shares': 100,
    'price': 490.91
}
r = "{0[name]} {0[shares]} {0[price]}".format(stock)

这些扩展中只允许使用名称,而不支持任意的表达式、方法调用和其他操作。另外,还可以指定格式说明符。方法是用一个冒号":"给每个占位符添加可选的格式说明符,例如:

r = "{name:8} {shares:8d} {price:8.2f}".format(name='GOOG', shares=100, price=490.10)

说明符的一般格式是[fill[align]][sign][0][width][.pricision][type],[ ]中的每个部分都是可选的。width说明符指定要使用的最小字段宽度,align说明符的值可取"<"、">"或"^"之一,分别代表在字段中左对齐、右对齐和居中对齐。fill是一个可选的填充字符,用于填充空白。type说明符表示数据的类型。格式说明符的sign部分是"+"、"-"或空格" "之一,表示符号。说明符的precision部分用于为十进制数提供精度位置。

4. 字典和集合操作

字典提供名称和对象之间的映射,它支持的操作如下:

操作 描述
x = d[k] 通过键进行索引
d[k] = x 通过键进行赋值
del d[k] 通过键删除一项
k in d 测试某个键是否存在
len(d) 字典中的项数

键的值可以是任意不可变对象,如字符串、数字和元组。另外,字典的键也可以是一列用逗号分开的值,例如:

d = {}
d[1, 2, 3] = "foo"
d[1, 0, 3] = "bar"
# 等价于
d[(1, 2, 3)] = "foo"
d[(1, 0, 3)] = "bar"

set和frozenset类型支持大量常见的集合操作,如下所示:

操作 描述
s | t s和t的并集
s & t s和t的交集
s - t 求差集
s ^ t 求对称差集
len(s) 集合中项数
max(s) 最大值
min(s) 最小值

并集、交集和差集操作的结果与最左边的操作数具有相同类型。例如,如果s是一个frozenset,而t是一个set,那么结果的类型将是frozenset。

5. 增量赋值

Python提供的增量赋值运算符如下所示:

操作 描述
x += y x = x + y
x -= y x = x - y
x *= y x = x * y
x /= y x = x / y
x //= y x = x // y
x **= y x = x ** y
x %= y x = x % y
x &= y x = x & y
x |= y x = x | y
x ^= y x = x ^ y
x >>= y x = x >> y
x <<= y x = x << y

增量赋值不会违反可变性或者原地修改对象。因此,执行代码 x += y时,将创建一个值为x + y的全新对象x。

6. 属性和函数调用运算符

点"."运算符用于访问对象的属性,例如

foo.x = 3
print(foo.y)
a = foo.bar(3, 4, 5)

表达式中可以出现多个点运算符,如foo.y.a.b。点运算符还可以用于函数的中间结果,如a = foo.bar(3, 4, 5).spam。
f(args)运算符用于调用f上的函数。函数的每个参数都是一个表达式。在调用函数前,将从左到右对所有参数表达式进行求值,这有时称为应用序求值。使用functools模块中的partial()函数可以对函数参数进行部分求值,例如:

def foo(x, y, z):
    return x + y + z
from functools import partial
f = partial(foo, 1, 2) # 为foo的参数x和y提供值
f(3) # 调用foo(1, 2, 3)

partial()函数对一个函数的某些参数求值,返回一个稍后可以调用的对象,以提供余下的参数。函数参数的部分求值与叫做科里化的过程关系十分紧密。所谓科里化的机制是:把一个带有多个参数的函数分解为一系列函数,其中每个函数带有其中一个参数。

7. 转换函数

有时必须在内置类型之间执行转换,只需用类型名称作为函数。另外,还有几个内置函数可用于执行特殊类别的转换。所有这些函数均返回一个新对象,该对象代表了转换后的值。

函数 描述
int(x [, base]) 将x转换为一个整数。如果x是一个字符串,base用于指定基数
float(x) 将x转换为一个浮点数
Complex(real [, imag]) 创建一个复数
str(x) 将对象x转换为字符串表示
repr(x) 将对象x转换为一个表达式字符串
format(x [, format_spec]) 将对象x转换为格式化的字符串
eval(str) 对字符串求值并返回对象
tuple(s) 将s转换为元组
list(s) 将s转换为列表
set(s) 将s转换为集合
dict(s) 创建字典。d必须是(key, value)元组的序列
frozenset(s) 将s转换为不可变集合
chr(x) 将整数转换为字符串
ord(x) 将字符转换为其整数值
hex(x) 将整数转换为十六进制字符串
bin(x) 将整数转换为二进制字符串
oct(x) 将整数转换为八进制字符串

需要注意的是,str()和reprt()函数返回的结果可能不同。repr()函数通常会创建一个表达式字符串,可以使用eval()对它求值以重新创建对象。ord()函数返回一个字符的整数顺序值。在Unicode中,这个值就是一个整数代码点。chr()函数用于将整数转换成字符。在创建容器的函数中,如list()、tuple()、set()等,参数可以是支持迭代的任意对象,而迭代生成的所有项将用于填充要创建的对象。

8. 布尔表达式与真值

and、or和not关键字构成了布尔表达式。这些运算符的行为如下所示:

运算符 描述
x or y 如果x为false,则返回y;否则返回x
x and y 如果x为false,则返回x;否则返回y
not x 如果x为false,则返回1;否则返回0

使用表达式来判断True或False值时,True、任意非零数字、非空字符串、列表、元组或字典都将返回True,而False、零、None和空的列表、元组和字典都将返回False。布尔表达式从左至右求值,而且只有需要时才会计算右边的操作数。

9. 对象的比较与身份

等于运算符(x == y)可以测试x和y的值是否相等。对于列表和元组,只有其中的所有元素都相等,它们才相等。而对于字典,只有当x和y的键都相同,而且键相同的所有对象的值都相等才会返回True。两个集合相等的条件是用==运算符进行比较时,它们具有相同的元素。
身份运算符(x is y和x is not y)可以测试两个对象是否引用了内存中的同一个对象。一般而言,x == y,但x is not y。
比较操作也可以在两个非兼容对象之间进行,如一个文件和一个浮点数,但返回结果是任意的,可能没有意义。另外也可能导致异常。

10. 运算优先级

Python运算符的操作顺序如下表:

运算符 名称
(...), [...], {...} 创建元组、列表和字典
s[i], s[i:j] 索引和切片
s.attr 属性
f(...) 函数调用
+x, -x, ~x 一元运算符
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 < y, x <= y 比较、身份和序列成员检查
x > y, x >= y
x == y, x != y
x is y, x is not y
x in s, x not in s
not x 逻辑非
x and y 逻辑与
x or y 逻辑或
lambda args: expr 匿名函数

运算顺序并非由上表的x和y的类型决定。因此,即便是用户自定义对象,也可以重新定义每个运算符。

11. 条件表达式

常见的编程模式是根据表达式的结果,有条件地进行赋值,例如:

if a <= b:
    minvalue = a
else:
    minvalue = b

使用条件表达式可以简化这段代码,例如:

minvalue = a if a <= b else b

在这类表达式中,首先求值的是中间的条件。如果结果为True,再对if语句左面的表达式求值,否则就会对else后面的表达式求值。

猜你喜欢

转载自blog.51cto.com/hanviseas/2158220