Python equivalent of Ruby's 'method_missing' Python equivalent of Ruby's 'method_missing' ruby ruby

Python equivalent of Ruby's 'method_missing'


There is no difference in Python between properties and methods. A method is just a property, whose type is just instancemethod, that happens to be callable (supports __call__).

If you want to implement this, your __getattr__ method should return a function (a lambda or a regular def, whatever suite your needs) and maybe check something after the call.


Python doesn't distinguish between methods and attributes (a.k.a. "instance variables") the way Ruby does. Methods and other object attributes are looked up in exactly the same way in Python -- not even Python knows the difference at the look-up stage. Until the attribute is found, it's just a string.

So if you're asking for a way to ensure that __getattr__ is only called for methods, I'm afraid you probably won't find an elegant solution. But it's easy enough to simply return a function (or even a brand-new dynamically bound method) from __getattr__.


You could implement a missing_method like feature in the below way:

https://gist.github.com/gterzian/6400170

import unittestfrom functools import partialclass MethodMissing:    def method_missing(self, name, *args, **kwargs):        '''please implement'''        raise NotImplementedError('please implement a "method_missing" method')    def __getattr__(self, name):        return partial(self.method_missing, name)class Wrapper(object, MethodMissing):    def __init__(self, item):        self.item = item    def method_missing(self, name, *args, **kwargs):        if name in dir(self.item):            method = getattr(self.item, name)            if callable(method):                return method(*args, **kwargs)            else:                raise AttributeError(' %s has not method named "%s" ' % (self.item, name))class Item(object):    def __init__(self, name):        self.name = name    def test(self, string):        return string + ' was passed on'class EmptyWrapper(object, MethodMissing):    '''not implementing a missing_method'''    passclass TestWrapper(unittest.TestCase):    def setUp(self):        self.item = Item('test')        self.wrapper = Wrapper(self.item)        self.empty_wrapper = EmptyWrapper()    def test_proxy_method_call(self):        string = self.wrapper.test('message')        self.assertEqual(string, 'message was passed on')    def test_normal_attribute_not_proxied(self, ):        with self.assertRaises(AttributeError):            self.wrapper.name            self.wrapper.name()    def test_empty_wrapper_raises_error(self, ):        with self.assertRaises(NotImplementedError):            self.empty_wrapper.test('message')if __name__ == '__main__':    unittest.main()