【问题标题】:Python - Variables snap back to original values when iteration is finishedPython - 迭代完成时变量会恢复到原始值
【发布时间】:2016-03-12 08:59:40
【问题描述】:

我已经编写了这段 sn-p 代码来说明问题。在代码本身下方,您可以看到控制台打印输出。

在我的程序中,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

【问题讨论】:

  • @R Nar 谢谢,已修复。
  • 赞成。见this SO QA

标签: python iteration overloading


【解决方案1】:

您的问题是因为您的 __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__ 用于就地运算符+=,然后应该像我的代码一样返回自身。

【讨论】:

  • 当然!谢谢!我很惊讶这个问题没有更早地让我感到震惊。
  • 这个答案可能适合特定需求(即增加对象a += b),但在其他情况下会失败/不符合预期(例如c = a + b
  • @Pynchia,非常好,非常重要的一点要指出。编辑为包含__iadd__
  • @Pynchia,@R Nar,我明白了。将定义两者。
【解决方案2】:

    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__ 直接更新属性,但是它修改了原始对象,它可能不适合其他类型的表达式:

例如

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 的编辑)

【讨论】:

  • 感谢您为我解决这个问题。我认为print(id(point)) 将来检查此类问题会派上用场。
  • 请查看我添加的注意事项
【解决方案3】:

你的问题是你重载的 Add 函数实际上并没有改变 self.x 和 self.y 的值。它返回一个表示这些添加的新向量。但是,这个新向量没有存储在 Points 列表中,它只是保存在变量 point 中。

更新您的重载添加,使其更新 self.x 和 self.y 的值,而不是返回一个新向量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-15
    • 1970-01-01
    • 2021-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多