質問

I have a Python class which has various internal variables that I want to expose as x, y, a simple example being:

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

I would have thought that this would not work because __getattr__ accesses members of self. However, everything works as long as I don't try to define a __setattr__ - even if I just make it equal to pass, I get recursion. How should I implement __setattr__? In particular, what should I be calling in the case that they key is not x or y?

Also, in general my question is whether this the right way of implementing the desired behavior such as:

v = Vec2()
# this
v.x = 1.0
v.y = 0.0
# or this
v[0] = 1.0
v[1] = 0.0

or whether there are better alternatives. I'm using python 2.7.5. Thanks!

役に立ちましたか?

解決

Don't use __getattr__ or __setattr__ for this. Properties are a better fit for your task:

# 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

The problem with your __setattr__ attempts is that __setattr__ is called for all attribute assignments, including self.data, self.mapping, and any assignments you attempt in __setattr__ itself. You can fix that by delegating to object.__setattr__ for attributes other than x or y, but properties are easier. Properties also save you from having to use object.__getattribute__ for attribute access in __getattr__, which was one of the factors contributing to your infinite recursion problems.

In contrast to __setattr__, properties only trigger when you try to access the attribute they control. An x property doesn't have to deal with accesses to attributes other than x, and you don't have to use alternative attribute access mechanisms when writing a property.

他のヒント

You can call object.__setattr__ explicitly to avoid recursion:

def __setattr__(self, key, value):
    object.__setattr__(self, key, value)
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top