Bob Ippolito (@etrepum) on Haskell, Python, Erlang, JavaScript, etc.

meta/instance method descriptor


This is odd, but I ran into a situation where I wanted to have a method be callable from both the class (as a metamethod) and the instance (as a normal instance method). The only decent way I could think of was to use a descriptor, here's an example:

class metainstancemethod(object):
    def __init__(self, instancemethod, metamethod):
        self.metamethod = metamethod
        self.instancemethod = instancemethod

    def __get__(self, frominstance, fromclass):
        if frominstance is None:
            return self.metamethod.__get__(fromclass, fromclass.__metaclass__)
        return self.instancemethod.__get__(frominstance, fromclass)

class Meta(type):
    def magic(self):
        print self, "metamagic"

class Minor(object):
    __metaclass__ = Meta
    def magic(self):
        print self, "magic"
    magic = metainstancemethod(magic, Meta.magic)


Phillip J. Eby came up with a better way to do this for PyProtocols. Basically, the descriptor goes on the metaclass rather than the class, which is less work and requires less magic. Check the comments (or PyProtocols) for his implementation. Thanks!