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