According to Python 2.7.12 documentation, User-defined methods:
User-defined method objects may be created when getting an attribute of a class (perhaps via an instance of that class), if that attribute is a user-defined function object, an unbound user-defined method object, or a class method object. When the attribute is a user-defined method object, a new method object is only created if the class from which it is being retrieved is the same as, or a derived class of, the class stored in the original method object; otherwise, the original method object is used as it is.
I know that everything in Python is an object, so a “user-defined method” must be identical to a “user-defined method object“. However, I can’t understand why there is a “user-defined function object attribute”. Say, in the following code:
class Foo(object): def meth(self): pass
meth
is a function defined inside a class body, and thus a method. So why can we have a “user-defined function object attribute”? Aren’t all attributes defined inside a class body?
Bouns question: Provide some examples illustrating how a user-defined method object is created by getting an attribute of a class. Isn’t objects defined in their class definition? (I know methods can be assigned to a class instance, but that’s monkey patching.)
I’m asking for help because this part of document is really really confusing to me, a programmer who only knows C, since Python is such a magical language that supports both functional programming and object-oriented programmer, which I haven’t mastered yet. I’ve done a lot of search, but still can’t figure that out.
Advertisement
Answer
When you do
class Foo(object): def meth(self): pass
you are defining a class Foo
with a method meth
. However, when this class definition is executed, no method object is created to represent the method. The def
statement creates an ordinary function object.
If you then do
Foo.meth
or
Foo().meth
the attribute lookup finds the function object, but the function object is not used as the value of the attribute. Instead, using the descriptor protocol, Python calls the __get__
method of the function object to construct a method object, and that method object is used as the value of the attribute for that lookup. For Foo.meth
, the method object is an unbound method object, which behaves like the function you defined, but with an extra type checking of self
. For Foo().meth
, the method object is a bound method object, which already knows what self
is.
This is why Foo().meth()
doesn’t complain about a missing self
argument; you pass 0 arguments to the method object, which then prepends self
to the (empty) argument list and passes the arguments on to the underlying function object. If Foo().meth
evaluated to the meth
function directly, you would have to pass it self
explicitly.
In Python 3, Foo.meth
doesn’t create an unbound method object; the function’s __get__
still gets called, but it returns the function directly, since Guido decided unbound method objects weren’t useful. Foo().meth
still creates a bound method object, though.