在Python中使用__setattr__进行属性别名

时间:2014-02-11 10:35:33

标签: python getattr setattr

我有一个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。谢谢!

2 个答案:

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

__getattr__相反,属性仅在您尝试访问其控制的属性时触发。 __setattr__属性不必处理对x以外的属性的访问,并且在编写属性时不必使用备用属性访问机制。