An example is used to analyze the parameter passing process of method in Python
- 2020-05-05 11:23:56
- OfStack
What is ?
function is a piece of code that can be called by name, and we can pass in parameters to get the return value. All parameters are passed explicitly.
method is a combination of function and objects. When we call a method, some arguments are passed implicitly. More on that later.
instancemethod
In [5]: class Human(object):
...: def __init__(self, weight):
...: self.weight = weight
...: def get_weight(self):
...: return self.weight
...:
In [6]: Human.get_weight
Out[6]: <unbound method Human.get_weight>
This tells us that get_weight is an unbound method. What is unbound? Keep reading.
In [7]: Human.get_weight()
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/home/yao/learn/insight_python/<ipython-input-7-a2b2c5cd2f8d> in <module>()
----> 1 Human.get_weight()
TypeError: unbound method get_weight() must be called with Human instance as first argument (got nothing instead)
An unbound method must be called with an Human instance as its first argument. So let's try
In [10]: Human.get_weight(Human(45))
Out[10]: 45
It worked, but we're used to it in general.
In [11]: person = Human(45)
In [12]: person.get_weight()
Out[12]: 45
The results are exactly the same. Let's take a look at the official documentation to explain this phenomenon.
When an instance attribute is referenced that isn't a data attribute, its class is searched.
If the name denotes a valid class attribute that is a function object, a method object is
created by packing (pointers to) the instance object and the function object just found together
in an abstract object: this is the method object. When the method object is called with an
argument list, a new argument list is constructed from the instance object and the argument list,
and the function object is called with this new argument list.
The usual call method (person.get_weight ()) passed the called instance hidden as a parameter self, self is just an ordinary parameter name, not a keyword.
In [13]: person.get_weight
Out[13]: <bound method Human.get_weight of <__main__.Human object at 0x8e13bec>>
In [14]: person
Out[14]: <__main__.Human at 0x8e13bec>
We see that get_weight is bound to the person instance object.
summarizes
classmethod
In [1]: class Human(object):
...: weight = 12
...: @classmethod
...: def get_weight(cls):
...: return cls.weight
In [2]: Human.get_weight
Out[2]: <bound method type.get_weight of <class '__main__.Human'>>
We see that get_weight is an method bound to the Human class. So let's call
In [3]: Human.get_weight()
Out[3]: 12
In [4]: Human().get_weight()
Out[4]: 12
Both the class and the instance of the class can call get_weight and the result is exactly the same.
We see that weight is a property of the Human class, and of course an instance of Human. Is cls a class or an instance?
In [1]: class Human(object):
...: weight = 12
...: @classmethod
...: def get_weight(cls):
...: print cls
In [2]: Human.get_weight()
<class '__main__.Human'>
In [3]: Human().get_weight()
<class '__main__.Human'>
We see that all the objects passed are Human classes, not instances of Human, and the results are no different. cls is just a normal function parameter that is implicitly passed when called.
summed up
staticmethod
In [1]: class Human(object):
...: @staticmethod
...: def add(a, b):
...: return a + b
...: def get_weight(self):
...: return self.add(1, 2)
In [2]: Human.add
Out[2]: <function __main__.add>
In [3]: Human().add
Out[3]: <function __main__.add>
In [4]: Human.add(1, 2)
Out[4]: 3
In [5]: Human().add(1, 2)
Out[5]: 3
We see that add is just a normal function on both classes and instances, and is not bound to any particular class or instance. It can be called using a class or an instance of a class without any implicit arguments being passed in.
In [6]: Human().add is Human().add
Out[6]: True
In [7]: Human().get_weight is Human().get_weight
Out[7]: False
add is also the same object on both instances. instancemethod, on the other hand, creates a new get_weight object each time.
summarizes