我编写了这段代码来说明问题。在代码本身下方,您可以看到控制台打印输出。
在我的程序中,Polygon类对象将顶点坐标存储在指向每个顶点的向量列表中。所有Translate()函数必须迭代遍历列表中的每个向量,并将参数向量添加到每个项目。简单,对吧?
Vector类有自己的重载__add__
函数。
当我编写并测试代码时,我发现该列表的成员只有在我迭代时才会改变。一旦完成,所有坐标都会恢复到原始值。
在我发现这个问题之后,我发现了另一个函数 - Manual_Translate(),它手工计算矢量分量(不调用Vector。__add__
)
class Vector():
def __init__(self, X, Y):
self.x = X
self.y = Y
def __add__(self, Other_Vector):
return Vector((self.x + Other_Vector.x),(self.y + Other_Vector.y))
class Polygon():
def __init__(self, point_list):
self.Points = []
for item in point_list:
self.Points.append (Vector(item[0], item[1]))
def Translate (self, Translation):
for point in self.Points:
point += Translation
print (point.x, point.y) #printout from the same loop
def Manual_Translate (self, Translation):
for point in self.Points:
point.x += Translation.x
point.y += Translation.y
print (point.x, point.y)
def Report (self):
for point in self.Points:
print (point.x, point.y) #printout from another loop
vertices = [[0,0],[0,100],[100,100],[100,0]]
Square = Polygon (vertices)
print ("A: we used __add__ function")
Square.Translate (Vector(115,139))
print ("")
Square.Report()
print ("\nB: we calculated vector sum by hand")
Square.Manual_Translate (Vector(115,139))
print ("")
Square.Report()
结果:
如果我使用__add__
,则值更改会丢失。如果我手工添加矢量 - 他们会留下来。我错过了什么? __add__
实际上是否与此问题有关?发生了什么事?
A: we used __add__ function
115 139
115 239
215 239
215 139
0 0
0 100
100 100
100 0
B: we calculated vector sum by hand
115 139
115 239
215 239
215 139
115 139
115 239
215 239
215 139
答案 0 :(得分:4)
您的问题是因为您的__add__
函数正在返回Polygon
的新实例,而不是实际更改实例的值。
return Vector((self.x + Other_Vector.x),(self.y + Other_Vector.y))
应改为:
self.x += Other_Vector.x
self.y += Other_Vector.y
return self
正如Pynchia指出的那样,这只能起作用,因为你假设正在调用+=
运算符。为了更好地适应所有类实现,明确定义__add__
和__iadd__
数据模型方法:
__add__
对于c = b + a
之类的内容应返回一个新实例,因此您的原始代码就可以了。
__iadd__
适用于就地操作符+=
,然后应该像我的代码一样返回。
答案 1 :(得分:1)
在
def Translate (self, Translation):
for point in self.Points:
point += Translation
print (point.x, point.y) #printout from the same loop
在增加之后,为名称point
分配一个新对象,即它引用一个新对象,该对象是它所引用的前一个对象(即列表中的元素)之和的结果,并且另一个对象(翻译),因为__add__
返回一个新实例。
因此永远不会触及原始列表元素。
然而,在
def Manual_Translate (self, Translation):
for point in self.Points:
point.x += Translation.x
point.y += Translation.y
print (point.x, point.y)
point
引用列表元素,如果改变其属性,则会改变原始对象。
尝试
def Translate (self, Translation):
for point in self.Points:
print(id(point))
point += Translation
print(id(point))
print (point.x, point.y) #printout from the same loop
@R Nar上面给出了一个解决方案,__add__
直接更新了属性,但它修改了原始对象,可能不适合其他类型的表达式:
e.g。
point_c = point_a + point_b
导致point_a
被修改,point_c
引用相同的对象(即point_a
)
实施例
>>> class A:
... def __init__(self,n):
... self.n = n
... def __add__(self,other):
... self.n = self.n + other.n
... return self
...
>>> a=A(2)
>>> b=A(3)
>>> c=a+b
>>> a
<__main__.A object at 0x7ff1b9bece10>
>>> a.n
5
>>> c
<__main__.A object at 0x7ff1b9bece10>
>>> c.n
5
所以,最好的办法是对__add__
和__iadd__
采取行动(参见@R Nar的编辑)
答案 2 :(得分:0)
问题在于,重载的Add函数实际上并没有改变self.x和self.y的值。它返回一个代表这些添加的新向量。但是,新的矢量并不存储在列表中,它只是保存在变量点中。
更新你的重载添加,以便它更新self.x和self.y的值,而不是返回一个新的向量。