Python 的内置 complex 表示复数,实部和虚部可分别通过 real、imag 读取。加、减、乘、除直接使用运算符;计算相位、极坐标或复数数学函数时,再导入 cmath。本文示例按 Python 3.11 编写。
创建复数并执行四则运算
跳转到“创建复数并执行四则运算”虚数常量写成 3j 或 3J;2 + 3j 是实数与虚数相加的表达式,complex(2, 3) 得到相同的值。数字与后缀之间不能插入空格,也不能把 image j 当成 Python 语法。变量 j 本身没有预定义为虚数单位。
| 操作 | 含义 | 例子 |
|---|---|---|
complex(real, imag) | 指定实部、虚部 | complex(2, 3) 得到 2+3j |
complex(real) | 虚部默认为零 | complex(4) 得到 4+0j |
+、- | 对应部分相加、相减 | (2+3j) + 4 |
*、/ | 复数乘法、除法 | (2+3j) / 4;不要求导入 cmath |
.real、.imag | 读取实部、虚部 | 内置 complex 返回 float |
abs(z) | 模,即到原点的距离 | abs(3+4j) 为 5.0 |
z.conjugate() | 共轭,虚部改变符号 | (3+4j).conjugate() 为 3-4j |
下面的程序定义了所有用到的变量,并使用 total 避免覆盖内置函数 sum:
z1 = complex(2, 3)z2 = complex(4)assert z1 == 2 + 3j == 2 + 3Jassert z2 == 4 + 0j
total = z1 + z2difference = z1 - z2product = z1 * z2quotient = z1 / z2assert total == 6 + 3jassert difference == -2 + 3jassert product == 8 + 12jassert quotient == 0.5 + 0.75j
z = 3 + 4jassert z.real == 3.0 and z.imag == 4.0assert isinstance(z.real, float) and isinstance(z.imag, float)assert abs(z) == 5.0assert z.conjugate() == 3 - 4jassert z * z.conjugate() == abs(z) ** 2print(total, difference, product, quotient)复数对象不可变。不能通过给 z.real 或 z.imag 赋值来修改它;需要重新构造,例如 complex(5, z.imag)。内置复数的两部分采用浮点表示,不能据此认为十进制小数或任意大整数都能精确保存。
相位与极坐标
跳转到“相位与极坐标”cmath.phase(z) 返回弧度角,cmath.polar(z) 返回 (模, 相位),cmath.rect(r, phi) 则从极坐标重建复数。相位不是角度制,显示为角度时可用 math.degrees。
import cmathimport math
z = 3 + 4jphase = cmath.phase(z)radius, angle = cmath.polar(z)restored = cmath.rect(radius, angle)assert math.isclose(radius, 5.0)assert math.isclose(phase, math.atan2(4, 3))assert math.isclose(math.degrees(angle), 53.13010235415598)assert cmath.isclose(restored, z, rel_tol=1e-12, abs_tol=1e-12)assert cmath.sqrt(-1) == 1j
# 负实轴两侧的有符号零影响相位的分支选择。above = complex(-1.0, 0.0)below = complex(-1.0, -0.0)assert cmath.phase(above) == math.piassert cmath.phase(below) == -math.piassert above == belowprint(radius, angle, restored)重建结果可能有浮点舍入误差,宜按问题要求使用 cmath.isclose 的容差。零复数没有唯一的数学方向;即使接口返回了某个数值,也不能把它当成测得的方向。负实轴上的正负零例子说明,相等的复数值仍可能保留影响分支选择的浮点符号信息。cmath 的极坐标与分支约定
能比较相等,不提供大小排序
跳转到“能比较相等,不提供大小排序”2+0j == 2 为真,但 Python 没有为复数定义 <、> 这样的自然大小顺序。若业务需要排序,应明确选择按模、实部或其他规则排序。// 和 % 也不适用于内置复数。
def raises(expected, operation): try: operation() except expected: return raise AssertionError(f"expected {expected.__name__}")
assert complex("2+3j") == 2 + 3jassert complex(" (2+3j) ") == 2 + 3jraises(ValueError, lambda: complex("2 + 3j"))raises(ZeroDivisionError, lambda: (2 + 3j) / 0j)raises(TypeError, lambda: (1 + 2j) < (2 + 1j))raises(TypeError, lambda: (1 + 2j) // 2)raises(TypeError, lambda: (1 + 2j) % 2)raises(AttributeError, lambda: setattr(1 + 2j, "real", 4))
assert 2 + 0j == 2assert sorted([3 + 4j, 1j, 2 + 0j], key=abs) == [1j, 2 + 0j, 3 + 4j]assert not bool(0j) and bool(1j)print("complex boundary checks passed")complex() 接受字符串时有自己的格式要求,不能先假定它会忽略字符串内部所有空格。四则运算与构造的完整规则见 Python 数值类型和 complex 内置函数。