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.