Python类方法参数错误:需4个位置参数却传入5个,求解决方案
解决Python实例方法调用的TypeError问题(粒子绕地模拟程序)
你遇到的TypeError核心原因是Python实例方法的第一个参数必须是self——当你用p.move(...)调用方法时,Python会自动把实例p作为第一个参数传递给方法,但你的move方法定义里没有预留这个参数,导致实际传入的参数数量比方法定义多1个。
修复步骤
- 给实例方法添加
self参数:所有通过实例调用的方法(比如move、result),第一个参数必须是self(约定俗成的命名,也可以用其他名称),用来指代当前实例本身。 - 用
self访问实例属性,避免冗余传参:你的r、rAng、v等都是实例p的属性,不需要在调用方法时手动传入,直接在方法内部用self.r、self.rAng获取即可。 - 更新实例状态:
move方法里计算出的新r、v、potE等值,需要赋值给self.r、self.v等属性,否则这些计算结果只是方法内部的局部变量,不会改变实例的状态。 - 修正循环中的时间累加逻辑:原来的
move方法里已经执行了Particle.t += Particle.dt,循环末尾又加了一次,会导致时间每次循环跳2秒,需要删除循环里的Particle.t += Particle.dt。
修正后的完整代码
import math class Particle: # 类变量(常量) G = 6.674e-11 # 引力常数 ME = 5.972e24 # 地球质量(kg) t = 0 # 起始时间 dt = 1 # 时间步长(秒) def __init__(self, r, rAng, v, vAng, potE, kinE, totalE): self.r = r self.rAng = rAng self.v = v self.vAng = vAng self.potE = potE self.kinE = kinE self.totalE = totalE def move(self): # 从实例属性获取当前状态 r = self.r rAng = self.rAng v = self.v vAng = self.vAng a = -Particle.G * Particle.ME / r**2 ax = a * math.cos(rAng) ay = a * math.sin(rAng) vx = v * math.cos(vAng) + ax * Particle.dt vy = v * math.sin(vAng) + ay * Particle.dt v_new = (vx**2 + vy**2) ** 0.5 vAng_new = math.atan2(vy, vx) rx = r * math.cos(rAng) + vx * Particle.dt + 0.5 * ax * Particle.dt**2 ry = r * math.sin(rAng) + vy * Particle.dt + 0.5 * ay * Particle.dt**2 r_new = (rx**2 + ry**2) ** 0.5 rAng_new = math.atan2(ry, rx) potE_new = -Particle.G * Particle.ME / r_new kinE_new = 0.5 * 1 * v_new**2 totalE_new = potE_new + kinE_new # 更新实例属性 self.r = r_new self.rAng = rAng_new self.v = v_new self.vAng = vAng_new self.potE = potE_new self.kinE = kinE_new self.totalE = totalE_new Particle.t += Particle.dt def result(self): print( f"t: {Particle.t: >7,d} s\n" f" r: {self.r/1000:6.3f} km\n" f" rAng: {(self.rAng*180/math.pi):6.1f}deg\n" f" totalE: {int(self.totalE*1.0E-6)}MJ\n" f" potE: {int(self.potE*1.0E-6)}MJ\n" f" kinE: {int(self.kinE*1.0E-6)}MJ" ) p = Particle(12748e03, 0, 5592, math.pi / 2, 0, 0, 0) while Particle.t < 13000: p.move() # 不需要传参,方法内部通过self获取实例属性 if Particle.t % 100 == 0: p.result() # 同理,直接调用
关键修改说明
move和result方法都添加了self作为第一个参数;move方法不再需要传入实例属性,而是通过self读取,计算后再赋值回self更新实例状态;result方法直接用self访问实例的r、totalE等属性,无需传参;- 修复了循环中重复累加时间的问题;
- 把
3.14159换成了math.pi,精度更高。
内容的提问来源于stack exchange,提问作者Daley
相关产品推荐
相关产品推荐

