Что меня только поразило, так это то, что так называемый метод класса и так называемый метод экземпляра - это просто функция с семантическим значением, примененная к ее первому параметру, который молча передается, когда функция вызывается как метод объект (то есть obj.meth()
).
Обычно этот объект должен быть экземпляром, но @classmethod
декоратор метода изменяет правила для передачи класса. Вы можете вызвать метод класса в экземпляре (это просто функция) - первым аргументом будет его класс.
Поскольку это просто функция , она может быть объявлена только один раз в любой заданной области (то есть в class
определении). Следовательно, если в качестве сюрприза для Rubyist следует, что у вас не может быть метода класса и метода экземпляра с одинаковым именем .
Учти это:
class Foo():
def foo(x):
print(x)
Вы можете позвонить foo
на экземпляр
Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>
Но не в классе:
Foo.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)
Теперь добавьте @classmethod
:
class Foo():
@classmethod
def foo(x):
print(x)
Вызов экземпляра теперь передает его класс:
Foo().foo()
__main__.Foo
как и при вызове класса:
Foo.foo()
__main__.Foo
Это единственное соглашение, которое предписывает использовать self
этот первый аргумент в методе экземпляра и cls
в методе класса. Я не использовал ни того, ни другого, чтобы проиллюстрировать, что это просто аргумент. В Ruby self
это ключевое слово.
Контраст с Ruby:
class Foo
def foo()
puts "instance method #{self}"
end
def self.foo()
puts "class method #{self}"
end
end
Foo.foo()
class method Foo
Foo.new.foo()
instance method #<Foo:0x000000020fe018>
Метод класса Python - это просто декорированная функция, и вы можете использовать те же методы для создания собственных декораторов . Декорированный метод оборачивает реальный метод (в случае @classmethod
его передачи дополнительный аргумент класса). Основной метод все еще там, скрытый, но все еще доступный .
сноска: я написал это после того, как столкновение имен между классом и методом экземпляра пробудило мое любопытство. Я далеко не эксперт по Python и хотел бы комментарии, если что-то из этого не так.