Extending objects through methods' __call__
Tim Peters
tim_one at email.msn.com
Sun May 16 21:42:45 EDT 1999
[Hrvoje Niksic]
> Something appears to be lacking in Python's class interface. If I
> have a class X and its instance x, then I can customize what x() will
> do (via X.__call__), what reading and assigning to x.foo will do (via
> X.__getattr__ and X.__setattr__), what reading and assigning to x[foo]
> will do (via X.__getitem__ and X.__setitem__) and a bunch of other
> things, but... I cannot tell what x.foo() will do, at least not
> without knowing all the foo's in advance. Or can I?
I'm not sure you're asking the question there you want to ask, but, if you
are, part of the *point* of OO is that you can't tell what x.foo() will do
via static inspection <wink>.
> I think it would be very nice if I were able to specify something
> like:
>
> class my_class:
> def somemethod():
> ...
> def someothermethod():
> ...
> def __methcall__(self, method, *args, **kwargs):
> # Handle all the method calls that are not named otherwise.
> ...
Closest you get today is that __getattr__ handles *all* attribute references
that aren't satisfied otherwise. As Mark said, it can't tell the difference
between data and method attr accesses; it's all or nothing.
> The practical implication of this would be that it would become
> trivial to write a wrapper around an intrinsic object. UserDict could
> be written like this:
>
> class UserDict:
> def __init__(self): self.data = {}
> def __methcall__(self, method, *args, **kwargs):
> return apply(self.data__methods__[method], args, kwargs)
>
> Would such a scheme work?
Alas no, but for a different reason: objects of builtin types don't use the
same dispatching code as class instances; this is the infamous "type/class
split" the healing of which is the sometimes-charter of the Types-SIG; for
starters,
>>> {}.__methods__
['clear', 'copy', 'get', 'has_key', 'items', 'keys', 'update', 'values']
>>>
That is, the builtin dicts don't have __getitem__ etc methods, so trying to
redirect a __getitem__ to one directly will simply blow up (with an
AttributeError). That's why UserDict & friends are needed now.
getattr-based delegation *does* work for Python classes, though:
class A:
def __init__(self, data): self.data = data
def x(self): return "x"
def y(self): return "y"
def __str__(self): return "A(" + str(self.data) + ")"
class B:
def __init__(self, data):
self.delegate = A(data)
def y(self): return "y'"
def __getattr__(self, attr):
# let the delegate handle everything else
return getattr(self.delegate, attr)
b = B('stuff')
print b.x(), b.y(), b.data, str(b)
That prints
x y' stuff A(stuff)
charades-ly y'rs - tim
More information about the Python-list
mailing list