Consider the following code.
class Foo:
def bar(self, x):
pass
foo1 = Foo()
foo2 = Foo()
foobar1 = foo1.bar
foobar2 = foo2.bar #What are foobar1 and foobar2?
print(foobar1 is foobar2) #prints False. Why?
On the one hand, I can see why foobar1
is not foobar2
–if I call foobar1(some_arg)
, the call should in general be independent of foo2
and vice versa. But don't foobar1
and foobar2
both refer to function object defined inside the class Foo
?
If method_name
is actually defined in the class object of object
's class, then <object>.<method_name>
is a "bound method" (or closure), which effectively wraps the function from the class method in order to provide <object>
as the self
argument. If method_name
is actually an attribute of <object>
, or if it has been marked with the @staticmethod
decorator, then <object>.<method_name>
just the function itself.
That's a bit of an oversimplification. There's lots more information in the Python reference manual (for example, in the "Callable objects" section of Section 3.2, The standard type hierarchy, and, iirc, in the Python tutorial. I hope this is a reasonable starting point, but for the nitty-gritty details and a full understanding of all the corner cases, you should probably read the authentic docs.
When you call foobar1
or foobar2
, you supply one argument and the function gets called with two arguments. How do you suppose that happens?
More specifically, when you call foobar1
, the method bar
will be passed foo1
as the self
argument, while when you call foobar2
, the method bar will be passed foo2
. That seems like magic, but it has a simple cause: when you extracted the bar
attribute from foo1
(foo1.bar
), Python noticed that it didn't come from foo1
itself; rather, it came from the class Foo
. Since it came from the class object, Python created a new function closure on the fly in which self
is bound to foo1
. Thus, when you later call the closure, the self
argument is filled in from the closure.
You don't even need foo2
to see that. Every time you ask for the bar
attribute of an instance of class Foo
, you get a new closure. But that doesn't happen when you ask for the bar
attribute of the class itself. In that case, the attribute bar
is directly available, and no closure is constructed:
>>> foo1.bar is foo1.bar
False
>>> Foo.bar is Foo.bar
True
You can see that these are different things:
>>> foo1.bar
<bound method Foo.bar of <__main__.Foo object at 0x7f9c8d8f27b8>>
>>> Foo.bar
<function Foo.bar at 0x7f9c8d8e5c80>
The first one is a "bound method" (where self
has been bound to a value), and the second one is just a garden variety function.
If you try to call Foo.bar
, you'll notice that you need to supply the self argument yourself, precisely because you're calling a function and not a closure:
>>> Foo.bar(42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: bar() missing 1 required positional argument: 'x'
>>> Foo.bar(foo1, 42)
>>>