2.3. 数学运算

Python 开箱即用就可以当作计算器使用。本页介绍你最常用到的运算符:数值上的算术运算、产生布尔值的比较运算、组合条件的逻辑运算符,以及用于硬件层面工作的位运算符。

2.3.1. 算术运算

作用于 intfloat 值的标准算术运算符:

  • + —— 加法

  • - —— 减法(或作为前缀表示取负:-x

  • * —— 乘法

  • / —— 除法。始终 返回一个 float,即使两个操作数都是整数。

  • // —— 向下取整除法。返回向负无穷方向取整的整数商。

  • % —— 取模(求余数)。

  • ** —— 幂运算(2 ** 10 等于 1024)。

>>> 7 / 2
3.5
>>> 7 // 2
3
>>> -7 // 2
-4
>>> 7 % 2
1
>>> 2 ** 16
65536

混合类型的算术运算会自动将整数提升为浮点数:

>>> 3 + 0.5
3.5

增强赋值将运算符与 = 结合起来,以紧凑的方式进行就地更新:

counter = 0
counter += 1                # equivalent to counter = counter + 1
counter *= 2                # works for *= /= //= %= **= too

运算符优先级遵循常规顺序:先 **,然后是一元 -,接着是 *///%,最后是 +-。不确定时就用括号——它们在运行时不会带来任何开销。

2.3.2. 比较运算

比较运算符返回一个 boolTrueFalse):

  • ==!= —— 等于 / 不等于。

  • <<=>>= —— 排序比较。

>>> 3 == 3
True
>>> 3 == 3.0
True
>>> 3 < 5 <= 5
True

最后一个示例是一个 链式 比较,它完全等价于 3 < 5 and 5 <= 5

警告

= 用于赋值;== 用于比较。表达式 if x = 5: 之所以是语法错误,正是因为 Python 拒绝悄无声息地混淆这两者。

2.3.3. 布尔逻辑

有三个运算符可以组合布尔值:

  • and —— 只有两边都为真时才为 True

  • or —— 任意一边为真时即为 True

  • not —— 对单个布尔值取反。

andor短路:一旦结果已经确定,它们就停止求值。False and slow_check() 永远不会调用 slow_check

andor 还会返回它们其中一个操作数,而不是字面的 TrueFalse,这让你能够紧凑地编写默认值:

name = user_name or "anonymous"   # "" / 0 / None are falsy

2.3.4. 位运算符

对于硬件工作——打包寄存器字段、屏蔽位、解析协议头——你会用到位运算符。它们作用于 int 的二进制表示:

  • & —— 按位与

  • | —— 按位或

  • ^ —— 按位异或

  • ~ —— 按位取反(一的补码)

  • << —— 左移

  • >> —— 右移

在读写这些内容时,十六进制和二进制字面量形式非常方便:

>>> 0b1100 & 0b1010
8                              # 0b1000
>>> 0b1100 | 0b1010
14                             # 0b1110
>>> 0xFF ^ 0x0F
240                            # 0xF0
>>> 1 << 8
256
>>> (0xABCD >> 8) & 0xFF
171                            # extract the high byte

每个位运算符都有对应的增强形式:|=&=^=<<=>>=

备注

and / or 作用于布尔值(或真值性);& / | 作用于位。不要把它们弄混。0b1100 and 0b1010 的结果是 0b1010,因为两个操作数都为真值——这通常不是你在操作位时想要的结果。

2.3.5. 实用的数值内置函数

有少数几个内置函数涵盖了运算符本身无法完成的常见数值操作:

  • round() —— 取最近的整数,或在给定第二个参数时取最近的 ndigits 位小数。round(x) 返回 intround(x, n) 返回 float。遇到正中间的情况(0.51.5 ……)会取最近的偶数,而不总是向上取整。

  • divmod() —— 在一次调用中返回 (quotient, remainder)。在把一个量拆分为多个单位时很方便(把秒拆成分和秒,把字节拆成页和偏移量)。

  • pow() —— 两参数形式与 ** 相同。三参数形式 pow(base, exp, mod) 在计算 (base ** exp) % mod 时不会真正生成那个庞大的中间值,这是对大指数进行模幂运算的唯一实用方法。

>>> round(3.7)
4
>>> round(3.14159, 2)
3.14
>>> round(0.5)               # ties go to even, not always up
0
>>> round(1.5)
2

>>> divmod(125, 60)          # 125 seconds = 2 min, 5 sec
(2, 5)
>>> minutes, seconds = divmod(125, 60)

>>> pow(3, 4)                # same as 3 ** 4
81
>>> pow(3, 100, 7)           # (3 ** 100) mod 7, efficient
4

整数到字符串的进制转换(binocthex)在 字符串方法与格式化 中介绍。

2.3.6. math 模块

常见的数学函数位于 math 模块中。导入它一次,然后通过点号名称调用其函数:

import math

print(math.sqrt(2))              # 1.4142135
print(math.sin(math.pi / 2))     # 1.0
print(math.floor(3.7))           # 3
print(math.log(100, 10))         # 2.0

MicroPython 的 math 模块涵盖了常见的函数(sqrtexplogsincostanatan2floorceilpie ……)。需要随机数时,请参阅 random 模块;对于定点位运算,上面的运算符通常就足够了。

2.3.7. 复数

对于需要虚部的数值工作,Python 提供了 complex 类型,并带有 j 后缀的字面量(1 + 2j)。cmath 模块对复数输入的支持与 math 相对应。两者在大多数 MicroPython 构建中都存在,但在摄像头工作中很少需要;这里主要是提一下它们,以免你在移植使用了它们的代码时感到意外。