Kivy官方Pong教程 - 使用向量(kivy.vector)

6
我一直在按照Kivy官方的PongApp教程(链接 - 整个程序代码在网页底部)进行学习,并遇到了一个我无法理解的问题。
我已经定义了move函数,用于在每一帧通过速度向量改变球的位置。代码如下:
def move(self):
    self.pos = Vector(*self.velocity) + self.pos

然而,当我把代码写成这样时:

def move(self):
    self.pos = self.pos + Vector(*self.velocity)

它会导致错误: ValueError: PongBall.pos 值的长度是不可变的。
为什么呢?难道它不应该是相同的吗?

你的意思是说,如果你用第一种方式编写代码,它可以工作,但如果你用第二种方式编写代码,它会抛出异常? - Michael0x2a
2个回答

7

self.pos是一个kivy.properties.ObservableReferenceList

当你试图设置这个属性时,它会检查新值是否与旧值的长度相同。

来自kivy.properties.ReferenceProperty

cdef check(self, EventDispatcher obj, value):
  cdef PropertyStorage ps = obj.__storage[self._name]
  if len(value) != len(ps.properties):
    raise ValueError('%s.%s value length is immutable' % (
      obj.__class__.__name__, self.name))

此外,kivy.properties.ObservableListlist 的子类。不幸的是,kivy.vector.Vector 也是,正如任何有 Python 经验的人所知道的那样,list.__add__ 连接它的参数。这意味着向 self.pos 添加向量是通过扩展而不是逐个添加元素来完成的,这会导致 self.pos 抱怨其长度正在改变。它以相反的方式工作,因为 Vector 重载了 __add__ 来进行逐元素加法。因为 Python 更喜欢使用 __add__ 而不是 __radd__,所以整个过程失败了。

5
我认为这是因为Vector类型覆盖了加法以执行向量加法,在第一种情况下调用了它的__add__,自动将self.pos(一个列表)视为另一个向量。
在第二种情况下,调用了self.pos的__add__,它不知道Vector类型,并尝试执行普通的列表加法,从而扩展了列表的长度。由于pos必须是固定长度的列表,所以此操作失败并出现了错误。
总之(如果我没错),问题在于+根据其参数的类型执行不同的操作。这通常不重要,但在这里却产生了很大的区别。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接