Python 运算符
1. 运算符优先级
| 运算符 | 描述 | 优先级 | 结合性 |
|---|---|---|---|
(expr...)、[expr...]、{key: value...}、{expr...} | 绑定或加圆括号的表达式,列表、字典、集合 | 18 | 左 |
x[i]、x[i:j]、x(args...)、x.attribute | 索引、切片、调用、属性引用 | 17 | 左 |
await x | await 表达式 | 16 | 左 |
** | 幂[1] | 15 | 右 |
+x、-x、~x | 正,负,按位非 NOT | 14 | 右 |
*、@、/、//、% | 乘,矩阵乘,除,整除,取余 | 13 | 左 |
+、- | 加和减 | 12 | 左 |
<<、>> | 移位 | 11 | 左 |
& | 按位与 AND | 10 | 左 |
^ | 按位异或 XOR | 9 | 左 |
| | 按位或 OR | 8 | 左 |
in、not in、is、is not、<、<=、>、>=、!=、== | 比较运算,包括成员检测和标识号检测 | 7 | 左 |
not x | 布尔逻辑非 NOT | 6 | 右 |
and | 布尔逻辑与 AND | 5 | 左 |
or | 布尔逻辑或 OR | 4 | 左 |
if ... else ... | 条件表达式 | 3 | 左 |
lambda | lambda 表达式 | 2 | 左 |
:= | 赋值表达式 | 1 | 左 |
2. 算术运算符
2.1 基本算术运算
python
# 加减乘除
a = 10 + 5 # 15
b = 10 - 5 # 5
c = 10 * 5 # 50
d = 10 / 5 # 2.0 (总是返回浮点数)
# 整除和取余
e = 10 // 3 # 3 (向下取整)
f = 10 % 3 # 1 (取余数)
# 幂运算
g = 2 ** 3 # 8
h = 2 ** -1 # 0.52.2 除法的注意事项
Python 3 中的除法 / 总是返回浮点数,即使两个操作数都是整数:
python
print(10 / 5) # 2.0,不是 2
print(9 / 2) # 4.5
# 如果需要整数结果,使用整除
print(10 // 5) # 2
print(9 // 2) # 4负数的整除向负无穷方向取整:
python
print(9 // 2) # 4
print(-9 // 2) # -5 (不是 -4)
print(9 // -2) # -5
print(-9 // -2) # 43. 比较运算符
3.1 链式比较
Python 支持链式比较,这是一个非常优雅的特性:
python
x = 5
# 传统写法
if x > 0 and x < 10:
print("x is between 0 and 10")
# Python 链式比较
if 0 < x < 10:
print("x is between 0 and 10")
# 更复杂的链式比较
a, b, c = 1, 2, 3
if a < b < c:
print("ascending order")3.2 身份运算符 is vs 相等运算符 ==
is 比较的是对象的身份(内存地址),== 比较的是对象的值:
python
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True (值相等)
print(a is b) # False (不是同一个对象)
print(a is c) # True (是同一个对象)
# 对于小整数和短字符串,Python 会复用对象
x = 256
y = 256
print(x is y) # True (小整数被缓存)
x = 257
y = 257
print(x is y) # False (大整数不被缓存)
# 检查 None 应该使用 is
if value is None:
print("value is None")4. 逻辑运算符
4.1 短路求值
Python 的逻辑运算符支持短路求值:
python
# and 运算符:如果第一个为假,不会计算第二个
def expensive_operation():
print("This is expensive")
return True
x = False
result = x and expensive_operation() # 不会打印 "This is expensive"
# or 运算符:如果第一个为真,不会计算第二个
x = True
result = x or expensive_operation() # 不会打印 "This is expensive"4.2 逻辑运算符返回值
Python 的逻辑运算符不一定返回布尔值,而是返回最后一个被求值的对象:
python
print(1 and 2) # 2
print(0 and 2) # 0
print(1 or 2) # 1
print(0 or 2) # 2
print(not 1) # False
print(not 0) # True
# 常用于提供默认值
name = ""
display_name = name or "Anonymous" # "Anonymous"
name = "Alice"
display_name = name or "Anonymous" # "Alice"5. 位运算符
5.1 基本位运算
python
a = 60 # 0011 1100
b = 13 # 0000 1101
print(a & b) # 12 = 0000 1100 (按位与)
print(a | b) # 61 = 0011 1101 (按位或)
print(a ^ b) # 49 = 0011 0001 (按位异或)
print(~a) # -61 = 1100 0011 (按位取反)
print(a << 2) # 240 = 1111 0000 (左移)
print(a >> 2) # 15 = 0000 1111 (右移)5.2 位运算的应用
python
# 判断奇偶
def is_odd(n):
return n & 1 == 1
# 交换两个数(不推荐,可读性差)
a, b = 5, 10
a = a ^ b
b = a ^ b
a = a ^ b
print(a, b) # 10, 5
# 判断 2 的幂
def is_power_of_two(n):
return n > 0 and (n & (n - 1)) == 0
print(is_power_of_two(8)) # True
print(is_power_of_two(10)) # False
# 获取最低位的 1
def get_lowest_bit(n):
return n & -n
print(bin(get_lowest_bit(12))) # 0b1006. 运算符重载
6.1 算术运算符重载
可以通过魔法方法重载运算符:
python
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __repr__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Vector(4, 6)
print(v1 * 3) # Vector(3, 6)6.2 比较运算符重载
python
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
return self.x == other.x and self.y == other.y
def __lt__(self, other):
return (self.x ** 2 + self.y ** 2) < (other.x ** 2 + other.y ** 2)
def __repr__(self):
return f"Point({self.x}, {self.y})"
p1 = Point(1, 2)
p2 = Point(1, 2)
p3 = Point(3, 4)
print(p1 == p2) # True
print(p1 < p3) # True7. 特殊运算符
7.1 海象运算符 :=
Python 3.8+ 引入的海象运算符(赋值表达式)可以在表达式中进行赋值:
python
# 传统写法
data = input("Enter something: ")
if len(data) > 10:
print("Too long")
# 使用海象运算符
if (n := len(data := input("Enter something: "))) > 10:
print(f"Too long: {n} characters")
# 在列表推导中使用
results = [y for x in range(10) if (y := x ** 2) > 50]
print(results) # [64, 81]7.2 矩阵乘法运算符 @
Python 3.5+ 引入了矩阵乘法运算符 @:
python
import numpy as np
a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6], [7, 8]])
# 矩阵乘法
c = a @ b
print(c)
# [[19 22]
# [43 50]]
# 等价于
c = np.matmul(a, b)8. 运算符优先级常见陷阱
8.1 位运算符优先级
位运算符的优先级低于比较运算符,这可能导致意外结果:
python
# 错误!
if flags & 0x01 == 0x01: # 相当于 flags & (0x01 == 0x01)
pass
# 正确
if (flags & 0x01) == 0x01:
pass8.2 幂运算符的结合性
幂运算符是右结合的:
python
print(2 ** 3 ** 2) # 512,相当于 2 ** (3 ** 2)
print((2 ** 3) ** 2) # 648.3 not 的优先级
not 的优先级低于比较运算符:
python
# 这两个是等价的
if not x == y:
pass
if not (x == y):
pass
# 如果想要 (not x) == y,必须加括号
if (not x) == y:
pass9. 成员运算符和身份运算符的性能
9.1 in 运算符的性能
不同数据结构的 in 运算符性能差异很大:
python
# 列表:O(n)
large_list = list(range(1000000))
print(999999 in large_list) # 较慢
# 集合:O(1)
large_set = set(range(1000000))
print(999999 in large_set) # 很快
# 字典:O(1)
large_dict = {i: i for i in range(1000000)}
print(999999 in large_dict) # 很快9.2 链式 isinstance 检查
使用元组可以简化多个类型检查:
python
# 传统写法
if isinstance(x, int) or isinstance(x, float) or isinstance(x, complex):
print("x is a number")
# 更简洁的写法
if isinstance(x, (int, float, complex)):
print("x is a number")10. 参考资料
幂运算符
**绑定的紧密程度低于在其右侧的算术或按位一元运算符,也就是说2**-1为0.5。 ↩︎