You can define three new ``magic'' methods in a class now:
__getattr__(self, name)
, __setattr__(self, name, value)
and __delattr__(self, name)
.
The __getattr__
method is called when an attribute access fails,
i.e. when an attribute access would otherwise raise AttributeError --
this is after the instance's dictionary and its class hierarchy
have been searched for the named attribute. Note that if this method
attempts to access any undefined instance attribute it will be called
recursively!
The __setattr__
and __delattr__
methods are called when
assignment to, respectively deletion of an attribute are attempted.
They are called instead of the normal action (which is to insert
or delete the attribute in the instance dictionary). If either of
these methods most set or delete any attribute, they can only do so by
using the instance dictionary directly -- self.__dict__
-- else
they would be called recursively.
For example, here's a near-universal ``Wrapper'' class that passes all
its attribute accesses to another object. Note how the
__init__
method inserts the wrapped object in
self.__dict__
in order to avoid endless recursion
(__setattr__
would call __getattr__
which would call
itself recursively).
class Wrapper: def __init__(self, wrapped): self.__dict__['wrapped'] = wrapped def __getattr__(self, name): return getattr(self.wrapped, name) def __setattr__(self, name, value): setattr(self.wrapped, name, value) def __delattr__(self, name): delattr(self.wrapped, name) import sys f = Wrapper(sys.stdout) f.write('hello world\n') # prints 'hello world'
A simpler example of __getattr__
is an attribute that is
computed each time (or the first time) it it accessed. For instance:
from math import pi class Circle: def __init__(self, radius): self.radius = radius def __getattr__(self, name): if name == 'circumference': return 2 * pi * self.radius if name == 'diameter': return 2 * self.radius if name == 'area': return pi * pow(self.radius, 2) raise AttributeError, name