Что меня поразило, так это то, что так называемый метод class и так называемый метод instance - это просто функция с семантическим значением, примененным к ее параметр, который передается без вывода сообщений, когда функция вызывается как метод объекта (т.е. 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 и хотел бы получить комментарии, если что-то из этого не так.