1

我有一个 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__访问了自我的成员。但是,只要我不尝试定义 a ,一切都会正常工作__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。谢谢!

4

2 回答 2

3

不要为此使用__getattr__或。属性更适合您的任务:__setattr__

# 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,以及您尝试的任何分配__setattr__本身。您可以通过委派object.__setattr__xor以外的属性来解决此问题y,但属性更容易。属性还使您不必使用object.__getattribute__中的属性访问__getattr__,这是导致无限递归问题的因素之一。

与 相比__setattr__,属性仅在您尝试访问它们控制的属性时触发。x属性不必处理对 以外的属性的访问,x并且您不必在编写属性时使用替代的属性访问机制。

于 2014-02-11T10:42:19.793 回答
3

您可以object.__setattr__显式调用以避免递归:

def __setattr__(self, key, value):
    object.__setattr__(self, key, value)
于 2014-02-11T10:42:01.073 回答