关于Python Vector2类的对象拆分逻辑及相关使用疑问
Vector2类相关疑问解答
先看定义的Vector2类代码:
class Vector2: def __init__(self, x=0, y=0): self.x = x self.y = y if hasattr(x, "__getitem__"): x, y = x # why can we do this? self._v = [float(x), float(y)] else: self._v = [float(x), float(y)] def __getitem__(self, index): return self._v[index] def __setitem__(self, index, value): self._v[index] = 1.0 * value def __str__(self): return "(%s, %s)"%(self.x, self.y)
疑问1:为什么if hasattr(x, "__getitem__"):分支里能执行x, y = x?
能进入这个分支的x一定是可迭代对象——Python中,只要对象实现了__getitem__(或__iter__)方法,就支持迭代拆包。这里要求x刚好包含2个元素,比如x是元组(10,20)、列表[5,6],甚至是另一个Vector2实例(因为Vector2自身实现了__getitem__),所以x, y = x本质是把x这个可迭代对象的两个元素分别赋值给左边的x和y变量,完成参数拆包。
疑问2:hasattr(x, "__getitem__")的作用是什么?
hasattr(x, "__getitem__")用来检查x对象是否拥有__getitem__方法。拥有这个方法意味着:
- 对象支持索引访问(比如
x[0]、x[1]); - 对象属于可迭代类型(可以被遍历或拆包)。
这段代码里用它判断用户是否传入了“复合参数”作为第一个参数,比如用户可能这样实例化:Vector2((100,200))或Vector2(Vector2(1,2)),此时进入分支把复合参数拆成x和y两个值,再存入self._v。
补充纠正:关于pygame blit()中使用v1[0]
之前误以为v1 = Vector2(100, 200)无法在pygame的blit()方法中用v1[0]指定x轴位置,实际是完全可行的:v1[0]和v1.x等价。因为Vector2实现了__getitem__方法,v1[0]会调用该方法返回self._v[0],而self._v初始化时就是用x、y转换后的float列表,所以v1[0]对应x坐标,v1[1]对应y坐标,符合pygame对位置参数的要求。
内容的提问来源于stack exchange,提问作者Nemo
相关产品推荐
相关产品推荐

