What is Python's equivalent of Ruby's method_missing
method? I tried using __getattr__
but this hook applies to fields too. I only want to intercept the method invocations. What is the Python way to do it?

- 31,404
- 26
- 119
- 182

- 90,905
- 62
- 285
- 365
4 Answers
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.

- 37,300
- 12
- 75
- 90
-
1Thanks. I found [this](http://venodesigns.net/2010/11/02/emulating-rubys-method_missing-in-python/) on a little googling. – missingfaktor Jul 15 '11 at 08:39
-
2For reference, the link in question gets around the ambiguity by defining a list of attribute names that should be considered methods (which sounds like it kinda defeats the purpose, since you could just _define_ each of those methods and delegate to a stub). – Mu Mind Oct 07 '12 at 16:23
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__
.
-
1For the same reason you would use `method_missing` in Ruby or `doesNotUnderstand` in Smalltalk. – missingfaktor Jul 15 '11 at 08:37
-
I understand why you would want to use `__getattr__`. I just don't understand why you "only want to intercept the method invocations". – senderle Jul 15 '11 at 08:44
-
My design didn't require intercepting field access, but it doesn't seem to be a big stumbling block. I find the solution provided by @Emil good enough for my requirements. – missingfaktor Jul 15 '11 at 08:53
-
2Ruby does not distinguish between methods and attributes at all - there is no such thing as an attribute in Ruby. – steenslag Jul 15 '11 at 17:00
-
1@steenslag, that sounds to me like a really bizarre claim. When I say "attribute" I mean "internal state". Are you claiming that objects in Ruby have no internal state? Or do you mean that the internal state of objects in Ruby is always private? That's true. I suppose in Ruby-speak an attribute is really an accessor method of an "instance variable". But since we're talking about Python, I'm using Python-speak. – senderle Jul 15 '11 at 17:19
-
1In Ruby terms, Python's `__getattr__` is somewhere between `method_missing` and overriding `Hash#[]` to do something special for missing keys. – Mark Reed Aug 31 '13 at 20:18
You could implement a missing_method like feature in the below way:
https://gist.github.com/gterzian/6400170
import unittest
from functools import partial
class 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'''
pass
class 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()

- 535
- 6
- 5
This solution creates a Dummy
object for which:
- every non-existing method will work and return
None
(even if you pass parameters) - you can also provide a dictionary with
methodname: defaultvalue
for methods that should return a specific default value
class Dummy:
def __init__(self, methods):
self.methods = methods
def __getattr__(self, attr):
defaultvalue = self.methods[attr] if attr in self.methods else None
return lambda *args, **kwargs: defaultvalue
def baz(self):
return 'custom'
d = Dummy({'foo': 1234})
print(d.foo()) # 1234
print(d.bar(1, 2, x=123, y=456)) # None
print(d.kjfdhgjf()) # None
print(d.baz()) # 'custom'

- 41,386
- 99
- 383
- 673
-
1
-
-
Note this isn't a dummy in the traditional sense (see e.g. https://tanzu.vmware.com/developer/guides/test-doubles/#dummy). – jonrsharpe Jun 15 '22 at 16:02
-
@jonrsharpe I used the term "dummy" in the general meaning that it is a class that does nothing but just answers a default value for each call of a method. – Basj Jun 15 '22 at 17:28