我有一个Python类,它有各种内部变量,我想公开为x,y,一个简单的例子是:
class Vec2:
def __init__(self):
self.data = [0.0, 0.0]
self.mapping = {'x':0, 'y':1}
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
def __getattr__(self, key):
if key in self.mapping:
return self.data[self.mapping[key]]
else:
raise AttributeError
def _setattr__(self, key, value):
# ?????
pass
我原本以为这不起作用,因为__getattr__
访问了自己的成员。但是,只要我不尝试定义__setattr__
,一切都有效 - 即使我只是使它等于pass
,我也会得到递归。我该如何实施__setattr__
?特别是,如果他们键不是x或y,我该怎么称呼?
另外,一般来说,我的问题是这是否是实现所需行为的正确方法,例如:
v = Vec2()
# this
v.x = 1.0
v.y = 0.0
# or this
v[0] = 1.0
v[1] = 0.0
或是否有更好的选择。我使用的是python 2.7.5。谢谢!
答案 0 :(得分:3)
您可以明确调用object.__setattr__
以避免递归:
def __setattr__(self, key, value):
object.__setattr__(self, key, value)
答案 1 :(得分:3)
请勿使用__getattr__
或__setattr__
。 Properties更适合您的任务:
# Inherit from object. This is important.
class Vec2(object):
def __init__(self):
self.data = [0.0, 0.0]
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, val):
self.data[index] = val
@property
def x(self):
return self.data[0]
@x.setter
def x(self, val):
self.data[0] = val
@property
def y(self):
return self.data[1]
@y.setter
def y(self, val):
self.data[1] = val
__setattr__
次尝试的问题是,所有属性分配都会调用__setattr__
,包括self.data
,self.mapping
以及您在{{1}中尝试的任何分配本身。您可以通过委派__setattr__
获取object.__setattr__
或x
以外的属性来解决此问题,但属性更容易。属性还使您不必在y
中使用object.__getattribute__
进行属性访问,这是导致无限递归问题的因素之一。
与__getattr__
相反,属性仅在您尝试访问其控制的属性时触发。 __setattr__
属性不必处理对x
以外的属性的访问,并且在编写属性时不必使用备用属性访问机制。