Следует учитывать, что в Python все является объектом . Установив, что легче понять, что происходит. Если у вас есть функция def foo(bar): print bar
, вы можете сделать spam = foo
и позвонить spam(1)
, получив, конечно, 1
.
Объекты в Python хранят свои атрибуты экземпляра в словаре с именем __dict__
с «указателем» на другие объекты. Поскольку функции в Python также являются объектами , они могут назначаться и управляться как простые переменные, передаваться другим функциям и т. Д. Реализация объектной ориентации в Python использует это преимущество и рассматривает методы как атрибуты, так как функции, которые находятся в __dict__
объекта.
Методы экземпляра ' первым параметром всегда является сам объект экземпляра , обычно называемый self
(но это можно назвать this
или banana
). Когда метод вызывается непосредственно в class
, он не привязан ни к какому экземпляру, поэтому вы должны указать ему объект экземпляра в качестве первого параметра (A.func(A())
). Когда вы вызываете связанную функцию (A().func()
), первый параметр метода, self
, является неявным, но за кулисами Python делает то же самое, что непосредственно вызывает несвязанную функцию и передает экземпляр объекта в качестве первого параметра.
Если это понятно, тот факт, что присвоение A.func = func
(которое за занавесом делает A.__dict__["func"] = func
) оставляет вас несвязанным методом, неудивительно.
В вашем примере cls
в def func(cls): pass
на самом деле будет передаваться экземпляр (self
) типа A
. Когда вы применяете classmethod
или staticmethod
декораторы ничего не делаете, кроме как берете первый аргумент, полученный во время вызова функции / метода, и преобразуете это во что-то еще, прежде чем вызывать функцию.
classmethod
принимает первый аргумент, получает объект class
экземпляра и передает его в качестве первого аргумента в вызов функции, тогда как staticmethod
просто отбрасывает первый параметр и вызывает функцию без него.