Python基础:复数类型complex应用场景详解
Python基础:复数类型complex应用场景详解
一、开篇:Python内置复数——一个被低估的特性
如果你不是数学或物理专业的,可能从高中毕业后就没再接触过复数。你可能会想:“我写程序永远用不到复数吧?”
不一定。复数在信号处理、图像处理、电子电路仿真、量子计算、3D图形学等领域都有实际应用。而Python是为数不多的内置复数类型的主流编程语言——在很多语言中你需要引入第三方库才能处理复数。
⌨️ 这篇文章有两个目的:一是让你了解Python中的复数怎么用,二是让你知道它在什么场景下有用。即使你平时用不到,了解Python有这个内置能力也是一件好事。
二、复数的数学基础回顾
2.1 5分钟复习复数
复数由两部分组成:实部(real part)和虚部(imaginary part)。形如:
a + bj (在数学中通常写作 a + bi,Python中用 j 代替 i)其中:
a是实部(一个实数)b是虚部系数(一个实数)j是虚数单位,满足 j² = -1
# Python中的复数z1=3+4j# 实部=3, 虚部=4z2=1-2j# 实部=1, 虚部=-2z3=5j# 纯虚数,实部=0(注意:不能写成 j5)z4=2+0j# 其实就是实数2(但类型是complex)⚠️ 注意:Python中使用j而不是数学中的i来表示虚数单位。这是工程领域的惯例(因为i常被用作电流的符号)。
三、Python中复数的创建
3.1 字面量方式
# 基本创建a=3+4jb=-1-2jc=5j# 等于 0 + 5jd=2-0j# 等于 2 + 0j# 注意:虚部系数必须紧挨着j# e = 1 + j # NameError!j被当作变量名e=1+1j# OK3.2 使用complex()函数
# 从一个参数z1=complex(5)# (5+0j)z2=complex(3.14)# (3.14+0j)# 从两个参数(实部, 虚部)z3=complex(3,4)# (3+4j)z4=complex(-1,2.5)# (-1+2.5j)# 从字符串(不能有空格!)z5=complex('3+4j')# (3+4j)z6=complex('-1-2j')# (-1-2j)z7=complex('5j')# 5jz8=complex('3')# (3+0j)# 这些会报错# complex('3 + 4j') # 字符串中有空格!# complex('3+4i') # Python用j,不是i3.3 获取实部和虚部
z=3+4jprint(z.real)# 3.0(注意:返回float类型)print(z.imag)# 4.0# 复数的共轭(虚部取反)print(z.conjugate())# (3-4j)四、复数的运算
4.1 基本算术运算
a=3+4jb=1-2j# 加法:(3+4j) + (1-2j) = 4+2jprint(a+b)# (4+2j)# 减法:(3+4j) - (1-2j) = 2+6jprint(a-b)# (2+6j)# 乘法:(3+4j)(1-2j) = 3-6j+4j-8j² = 3-2j+8 = 11-2jprint(a*b)# (11-2j)# 除法:(3+4j)/(1-2j)print(a/b)# (-1+2j)# 幂运算print(a**2)# (-7+24j) — 因为 (3+4j)² = 9+24j+16j² = 9+24j-16 = -7+24j4.2 比较运算
a=3+4jb=3+4j# 可以比较相等print(a==b)# Trueprint(a!=b)# False# 不能比较大小!# print(a > b) # TypeError: '>' not supported between complex numbers# print(a < b) # 同上⚠️ 复数不能比较大小——这在数学上就没有意义。复数之间只能判断相等或不等。
4.3 内置函数对复数的支持
importmathimportcmath# 复数的数学函数z=3+4j# abs():复数的模(magnitude)# |3+4j| = sqrt(3² + 4²) = sqrt(25) = 5print(abs(z))# 5.0# pow():幂运算print(pow(z,2))# (-7+24j)# round()不能用于复数# round(z) # TypeError# cmath模块:复数的数学函数print(cmath.sqrt(z))# (2+1j)(因为(2+j)² = 4+4j+j² = 3+4j)# 复数的极坐标表示print(cmath.polar(z))# (5.0, 0.9272952180016122)# 返回 (模, 辐角) = (5.0, arctan(4/3))# 从极坐标恢复复数modulus,angle=5.0,0.9272952180016122print(cmath.rect(modulus,angle))# (3+4j)# 欧拉公式:e^(jx) = cos(x) + j*sin(x)x=0.5print(cmath.exp(1j*x))# (0.87758+0.47943j)print(complex(cmath.cos(x),cmath.sin(x)))# 手动计算验证4.4 cmath模块常用函数
importcmath z=1+1j# 指数和对数print(cmath.exp(z))# e^zprint(cmath.log(z))# ln(z)print(cmath.log10(z))# log10(z)# 三角函数print(cmath.sin(z))print(cmath.cos(z))print(cmath.tan(z))# 反三角函数print(cmath.asin(z))print(cmath.acos(z))print(cmath.atan(z))# 双曲函数print(cmath.sinh(z))print(cmath.cosh(z))print(cmath.tanh(z))# 判断函数print(cmath.isinf(complex(float('inf'),0)))# Trueprint(cmath.isnan(complex(float('nan'),0)))# Trueprint(cmath.isclose(1+2j,1+2.0000000001j))# True五、复数的实际应用场景
5.1 信号处理:傅里叶变换
importcmathdefdiscrete_fourier_transform(samples):""" 离散傅里叶变换(DFT) 输入:时域信号采样点列表(实数) 输出:频域复数列表 """n=len(samples)result=[]forkinrange(n):# 计算第k个频率分量frequency_component=0jfortinrange(n):angle=-2*cmath.pi*1j*k*t/n frequency_component+=samples[t]*cmath.exp(angle)result.append(frequency_component)returnresult# 示例:分析一个包含两个频率成分的信号importmath# 生成采样信号:50Hz + 120Hz的正弦波sample_rate=500# 采样率duration=1.0# 1秒n_samples=int(sample_rate*duration)samples=[]foriinrange(n_samples):t=i/sample_rate value=math.sin(2*math.pi*50*t)+0.5*math.sin(2*math.pi*120*t)samples.append(value)# 执行DFTfrequency_spectrum=discrete_fourier_transform(samples)# 显示前10个频率分量的幅度print('频率分析结果:')foriinrange(10):magnitude=abs(frequency_spectrum[i])frequency=i*sample_rate/n_samplesprint(f'{frequency:.0f}Hz: 幅度={magnitude:.2f}')5.2 图像处理:复数表示像素值
# 在图像处理中,可以使用复数来表示二维坐标系中的点# 复数的实部表示x坐标,虚部表示y坐标defrotate_point(x,y,angle_degrees):"""用复数实现二维平面上的点旋转"""# 创建表示点的复数point=complex(x,y)# 创建旋转因子:e^(jθ) = cos(θ) + j*sin(θ)importmath angle_radians=math.radians(angle_degrees)rotation=complex(math.cos(angle_radians),math.sin(angle_radians))# 旋转:复数乘法rotated=point*rotationreturnrotated.real,rotated.imag# 测试:将点(1, 0)旋转90度x,y=rotate_point(1,0,90)print(f'(1, 0)旋转90度后:({x:.2f},{y:.2f})')# (0.00, 1.00)# 放大/缩小defscale_point(x,y,factor):"""缩放点"""point=complex(x,y)scaled=point*factorreturnscaled.real,scaled.imag x,y=scale_point(3,4,2)print(f'(3, 4)放大2倍:({x},{y})')# (6.0, 8.0)5.3 电路分析:阻抗计算
# 在交流电路分析中,阻抗(电阻+电抗)用复数表示# Z = R + jX# R:电阻(实部),X:电抗(虚部)# 电感:X_L = jωL,电容:X_C = 1/(jωC) = -j/(ωC)defimpedance_resistor(r):"""纯电阻阻抗"""returncomplex(r,0)defimpedance_inductor(inductance,frequency):"""电感阻抗:Z_L = jωL"""omega=2*3.14159*frequencyreturncomplex(0,omega*inductance)defimpedance_capacitor(capacitance,frequency):"""电容阻抗:Z_C = 1/(jωC)"""omega=2*3.14159*frequencyreturncomplex(0,-1/(omega*capacitance))defparallel_impedance(z1,z2):"""并联阻抗"""return(z1*z2)/(z1+z2)defseries_impedance(*impedances):"""串联阻抗"""returnsum(impedances)# 示例:RLC串联电路R=100.0# 100欧姆电阻L=0.1# 100毫亨电感C=10e-6# 10微法电容f=1000.0# 1000Hz频率Z_R=impedance_resistor(R)Z_L=impedance_inductor(L,f)Z_C=impedance_capacitor(C,f)Z_total=series_impedance(Z_R,Z_L,Z_C)print(f'总阻抗:{Z_total}')print(f'阻抗模:{abs(Z_total):.2f}欧姆')print(f'相位角:{cmath.phase(Z_total):.2f}弧度')5.4 分形生成:曼德勃罗集
defmandelbrot(c,max_iterations=100):""" 判断一个复数c是否属于曼德勃罗集 返回迭代次数(用于着色),如果在max_iterations内不发散则返回max_iterations """z=0jforninrange(max_iterations):z=z*z+cifabs(z)>2:returnnreturnmax_iterationsdefgenerate_mandelbrot(width=80,height=40,max_iter=50):"""生成曼德勃罗集的ASCII艺术"""x_min,x_max=-2.0,1.0y_min,y_max=-1.0,1.0foryinrange(height):line=''forxinrange(width):# 将像素坐标映射到复数平面real=x_min+(x/width)*(x_max-x_min)imag=y_min+(y/height)*(y_max-y_min)c=complex(real,imag)# 计算这个点属于曼德勃罗集的程度m=mandelbrot(c,max_iter)# 用不同字符表示不同深度ifm==max_iter:line+='#'elifm>max_iter*0.8:line+='*'elifm>max_iter*0.5:line+='+'elifm>max_iter*0.2:line+='.'else:line+=' 'print(line)# 生成曼德勃罗集(终端中的ASCII艺术)generate_mandelbrot(100,40)六、复数的类型转换
# 复数 → 其他类型z=3+4j# 复数 → 字符串print(str(z))# '(3+4j)'# 复数 → 整数/浮点数?不行# int(z) # TypeError# float(z) # TypeError# 但可以取模magnitude=abs(z)# 5.0(float类型)# 其他类型 → 复数print(complex(5))# (5+0j)print(complex(3.14))# (3.14+0j)print(complex(3,4))# (3+4j)print(complex('1+2j'))# (1+2j)七、使用复数的注意事项
7.1 虚部符号问题
importcmath# 对负数开方# math.sqrt(-1) # ValueErrorresult=cmath.sqrt(-1)# 1jprint(result)# 但cmath.sqrt返回复数print(cmath.sqrt(4))# (2+0j)——即使结果是实数,也返回complex类型print(cmath.sqrt(-4))# 2j——令人困惑的写法,实际是0+2j# 如果你想要实数,需要检查defsafe_sqrt(x):"""安全开方:正数返回float,负数返回complex"""ifx>=0:importmathreturnmath.sqrt(x)else:returncmath.sqrt(x)print(safe_sqrt(4))# 2.0print(safe_sqrt(-4))# 2j7.2 复数的实部和虚部都是float
z=3+4jprint(type(z.real))# <class 'float'>print(type(z.imag))# <class 'float'># 这意味着实部或虚部也可以是float中的特殊值z1=complex(float('inf'),0)# (inf+0j)z2=complex(0,float('nan'))# (nanj)print(z1,z2)八、本篇小节
✅ Python内置复数类型——一个你可能不常用到但在需要时非常方便的特性:
- 创建方式:字面量
3+4j或complex(3, 4)或complex('3+4j') - 基本运算:加减乘除、幂运算都支持,但不能比较大小
- cmath模块:提供复数的sin、cos、exp、log、sqrt等函数
- 实际应用:信号处理(傅里叶变换)、图像旋转、电路分析、分形生成
- 注意点:虚部系数必须紧挨j(
4j而不是4 j)、Python用j不是i
💡 复数是Python"内置电池"理念的又一个体现。你可能90%的日常开发中用不到它,但当你的项目涉及信号处理、科学计算或图形学的时候,Python不用你额外装任何库就能搞定复数运算。下一篇我们来学习布尔类型bool。
