I have the following snippet:
class Meta(type):
def __getattr__(self, name):
pass
class Klass(object):
__metaclass__ = Meta
def get(self, arg):
pass
Now, if I do:
kls = Klass()
kls.get('arg')
everything works as expected (the instance method get
is called).
But if I do:
Klass.get('arg')
again the instance method is found and an exception is given, since it is treated as an unbound method.
How can I make a call to Klass.get('arg')
go through the __getattr__
defined in the metaclass? I need this because I want to proxy all methods called on a class to another object (this would be done in __getattr__
).
You'll have to look up the method on the type and pass in the first (
self
) argument manually:This problem is the very reason that special method names are looked up using this path; custom classes would not be hashable or representable themselves if Python didn't do this.
You could make use of that fact; rather than use a
get()
method, use__getitem__
, overloading[..]
indexing syntax, and have Python do thetype(ob).methodname(ob, *args)
dance for you:and then
Klass()['arg']
andKlass['arg']
work as expected.However, if you have to have
Klass.get()
behave differently (and the lookup for this to be intercepted byMeta.__getattribute__
) you have to explicitly handle this in yourKlass.get
method; it'll be called with one argument less if called on the class, you could make use of that and return a call on the class:You could also handle this in a descriptor that mimics method objects:
and use this as a decorator:
and it'll redirect look-ups to the metaclass if there is no instance to bind to:
Applying the decorator can be done in the metaclass:
and you can then add methods to classes using this metaclass without having to worry about delegation: