method missing in Python
Python doesn’t provide such thing as Ruby’s method_missing.
But you can impelment one with some Python magics.
Ruby’s method_missing
Ruby’s method_missing function gives you access inside Ruby object to hanle situation when a method doesn’t exist.
class Dog
def bark() # instance method
puts "wang wang !!!"
end
def method_missing(method_name, *arguments, &block) # instance method missing
puts 'needs this instance method #{method_name}'
end
def self.bark() # class method
puts "wang wang !!!"
end
def self.method_missing(method_name, *arguments, &block) # class method missing
puts 'needs this class method #{method_name}'
end
end
dog = Dog.new
dog.bark() # => wang wang !!!
dog.speak() # => needs this instance method speak
Dog.bark() # => wang wang !!!
Dog.speak() # => needs this class method speak
So if you want to create methods dynamically, you could put whatever logic you want inside method_missing. For example:
class Dog
def method_missing(method_name, *arguments, &block)
if method_name =~ /^(speak|say|sing|bark).*/
puts "wang wang !!!"
end
end
end
dog = Dog.new
dog.sing # => wang wang !!!
dog.say # => wang wang !!!
dog.bark # => wang wang !!!
dog.speak # => wang wang !!!
There’s no such thing as method_missing in Python. To implement method_missing you need to have a better understanding of Python innards.
Python instance method missing
Here’s the answer first.
# instance method missing, for Python 3.x
class Dog():
def bark(self):
print("wang wang !!!")
def __getattr__(self, name):
def _method_missing(*args, **kwargs):
print("needs this instance method %s" % name)
return _method_missing
dog = Dog()
dog.bark() # => wang wang !!!
dog.speak("A", "B", last="C") # => needs this instance method speak
# notes: "A", "B" stored in *args; last="C" stores in **kwargs
What’s happenning under the hood when you invoke dog.speak() in Python?
Here’s a very good stackoverflow answer.
o.f(x) is a two-step operation:
1) get the attribute defined in `o`.
2) call it with parameter x.
If the first step fails when there's no attribute `f`,
then `__getattr__` will be invoked.
And, what `__getattr__` returns must be callable.'
That's why you need to return a method definition instead of a value.
So when you call dog.speak(), __getattr__ will be invoked, and you need to make sure the return is callable.
It’s not that elegant, but straightforward engouth.
Python class method missing
Here’s the answer first
# class method missing, for python 3.x
class Animal(type):
def __getattr__(self, name):
def _method_missing(*args, **kwargs):
print("needs this class method %s" % name)
return _method_missing
class Dog(metaclass=Animal):
@classmethod
def bark(cls):
print("wang wang !!!")
Dog.bark() # => wang wang !!!
Dog.speak("A", "B", last="C") # => needs this class method speak
# notes: "A", "B" stored in *args; last="C" stores in **kwargs
How to understand it?
type and metaclass
As everything in Python is an object, class itself is an object as well. Then who is the class of Dog class? Or Dog class is the instance of who?
The answer is built-in class type, type serves the role of being the class of classes.
dog.__class__ # => <class '__main__.Dog'>
Dog.__class__ # => <class 'type'>
Actually, tuple, list, int, float are all objects, they’re all instances of type.
int.__class__ # => <class 'type'>
tuple.__class__ # => <class 'type'>
list.__class__ # => <class 'type'>
float.__class__ # => <class 'type'>
So !!! Let’s do a comparison.
dog is instance of Dog class, and Dog class is instance of type.
If cannot find speak in dog object, then Dog class __getattr__ will be invoked (as shown in instance-method-missing example),
If cannot find speak in Dog class, then type __getattr__ will be invoked.
You cannot change type’s __getattr__ as it’s buit-in.
But you can change Dog class’s class by assign it’s metaclass to other value.
# ...
class Dog(metaclass=Animal): # << -- change class's class.
@classmethod # notes: Animal must inherit from type.
def bark(cls):
print("wang wang !!!")
Now Animal class is the class of Dog class. Animal class __getattr__ will be invoked if Dog class’s speak cannot be found.
If you want to know more on metaclass, here’s a very good tutorial: python metaclass by example.