fonini fonini - 7 months ago 7
Python Question

Python classmethods: what's the difference between a member of an instance and a member of the class?

In python,

staticmethod
s are "just functions", and I can refer to them in two different ways:

>>> class A:
... @staticmethod
... def f():
... pass
...
>>> a=A()
>>> A.f
<function A.f at 0x7f20f8cd3f28>
>>> a.f
<function A.f at 0x7f20f8cd3f28>
>>> a.f is A.f
True


Both
a.f
and
A.f
are names that refer to the same object, which happens to be "just a function". Great.

Now, say I have a
classmethod
:

>>> class B:
... @classmethod
... def f(cls):
... pass
...
>>> b=B()
>>> b.f is B.f
False


I know that
b.f
and
B.f
are not functions: they're bound mothods. This means that the
cls
argument is implicit, and is always equal to
B
. Because of this, I would understand that if
B2
is a subclass of
B
,
B2().f is B().f
would be false, because they're bound methods with different
cls
arguments. But I don't understand why
B().f is B.f
yields
False
. Shouldn't they be the same object, just like
A().f
and
A.f
?

EDIT: This question is not the same as "What is the difference between @staticmethod and @classmethod in Python?". I know the difference between
staticmethod
and
classmethod
. I want to know one specific thing, which is not addressed in the "umbrella" question linked.

Answer

B().f and B.f are different objects because Python creates a new bound method object each time you refer to a non-static method via attribute access.

For example, B.f is B.f is also False.

>>> B.f is B.f
False

Similarly, you will get a new method object even if the instance stays the same:

>>> b = B()
>>> b.f is b.f
False

Static methods are plain functions, they don't need to be wrapped in a special method object. Therefore, A.f always returns the same f function object.