Python中同类型对象作为方法参数传递及实例异常变更原因排查
问题描述
我正在用Python创建一个表示三维点的类(我知道已有相关库可实现,这只是类的练习)。我希望实现一个能将一个点的坐标与另一个点相加的方法,尝试通过将另一个点作为方法参数来实现。编写的代码如下:
class Point: crd = [0,0,0] def add_vector(self, coord = [], *args) : self.crd[0] += coord[0] self.crd[1] += coord[1] self.crd[2] += coord[2] def subtract_point_from_point(self, other) : self.crd[0] = self.crd[0] - other.crd[0] self.crd[1] = self.crd[1] - other.crd[1] self.crd[2] = self.crd[2] - other.crd[2]
测试代码:
a = Point() b = [2, 2, 4] a.add_vector(b) print('Before making c:') print('a.crd: ' + str(a.crd[0])) print('a.crd: ' + str(a.crd[1])) print('a.crd: ' + str(a.crd[2])) c = Point() d = [7, 7, 9] c.add_vector(d) print('After adding d to c:') print('a.crd: ' + str(a.crd[0])) print('a.crd: ' + str(a.crd[1])) print('a.crd: ' + str(a.crd[2])) a.subtract_point_from_point(c) print('After making c: ') print('a.crd: ' + str(a.crd[0])) print('a.crd: ' + str(a.crd[1])) print('a.crd: ' + str(a.crd[2]))
运行结果:
Before making c: a.crd: 2 a.crd: 2 a.crd: 4 After adding d to c: a.crd: 9 a.crd: 9 a.crd: 13 After making c: a.crd: 0 a.crd: 0 a.crd: 0
疑问:
- 为什么给实例c添加向量d时,实例a的坐标会发生变化?
- 如何在Python中将同类型对象作为方法参数传递?
解答
1. 实例a坐标变化的原因
你定义的crd = [0,0,0]是类属性,不是实例属性。类属性属于整个类,所有该类的实例会共享同一个类属性对象。也就是说,a.crd和c.crd指向的是同一个列表,修改其中一个实例的crd,本质上是修改了这个共享的列表,另一个实例的crd自然会同步变化。
要解决这个问题,需要把crd改为每个实例独有的属性,在类的__init__方法中初始化:
class Point: def __init__(self): # 每个实例初始化时创建自己的坐标列表 self.crd = [0, 0, 0] # 后续方法逻辑保持不变 def add_vector(self, coord = [], *args) : self.crd[0] += coord[0] self.crd[1] += coord[1] self.crd[2] += coord[2] def subtract_point_from_point(self, other) : self.crd[0] = self.crd[0] - other.crd[0] self.crd[1] = self.crd[1] - other.crd[1] self.crd[2] = self.crd[2] - other.crd[2]
2. 传递同类型对象作为方法参数
你的subtract_point_from_point方法其实已经在接收同类型对象other了,只是之前的类属性问题导致结果不符合预期。修正属性问题后,可以进一步完善相关方法,比如实现点与点相加的功能:
新增一个add_point方法,直接接收另一个Point实例作为参数:
def add_point(self, other_point): self.crd[0] += other_point.crd[0] self.crd[1] += other_point.crd[1] self.crd[2] += other_point.crd[2]
调用时直接传入Point实例即可:
p1 = Point() p1.crd = [1, 2, 3] p2 = Point() p2.crd = [4, 5, 6] p1.add_point(p2) print(p1.crd) # 输出 [5, 7, 9]
另外,你的add_vector方法存在默认参数陷阱——Python中默认参数只会初始化一次,多次调用时如果修改了默认的空列表,后续调用会使用修改后的列表。建议修改为:
def add_vector(self, coord=None, *args): if coord is None: coord = [0, 0, 0] self.crd[0] += coord[0] self.crd[1] += coord[1] self.crd[2] += coord[2]
内容的提问来源于stack exchange,提问作者Isaiah Blanks
相关产品推荐
相关产品推荐

