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.