Was mich gerade von Ruby getroffen hat, ist diese sogenannte Klasse und eine sogenannte Instanzmethode nur eine Funktion mit semantischer Bedeutung ist, die auf ihren ersten Parameter angewendet wird, der stillschweigend übergeben wird, wenn die Funktion als Methode von aufgerufen wird ein Objekt (dhobj.meth()
).
Normalerweise muss dieses Objekt eine Instanz sein, aber der @classmethod
Methodendekorator ändert die Regeln, um eine Klasse zu übergeben. Sie können eine Klassenmethode für eine Instanz aufrufen (es ist nur eine Funktion) - das erste Argument ist ihre Klasse.
Weil es nur ein ist Funktion handelt , kann sie in einem bestimmten Bereich (dh einer class
Definition) nur einmal deklariert werden . Es folgt daher als Überraschung für einen Rubyisten, dass Sie keine Klassenmethode und keine Instanzmethode mit demselben Namen haben können .
Bedenken Sie:
class Foo():
def foo(x):
print(x)
Du kannst anrufen foo
eine Instanz
Foo().foo()
<__main__.Foo instance at 0x7f4dd3e3bc20>
Aber nicht in einer Klasse:
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)
Fügen Sie nun hinzu @classmethod
:
class Foo():
@classmethod
def foo(x):
print(x)
Das Aufrufen einer Instanz übergibt jetzt ihre Klasse:
Foo().foo()
__main__.Foo
ebenso wie das Aufrufen einer Klasse:
Foo.foo()
__main__.Foo
Es ist nur die Konvention, die vorschreibt, dass wir self
für dieses erste Argument eine Instanzmethode verwenden undcls
eine Klassenmethode verwenden. Ich habe beides hier nicht verwendet, um zu veranschaulichen, dass es nur ein Argument ist. In Ruby self
ist ein Schlüsselwort.
Kontrast zu 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>
Die Python-Klassenmethode ist nur eine dekorierte Funktion, und Sie können dieselben Techniken verwenden, um Ihre eigenen Dekoratoren zu erstellen . Eine dekorierte Methode umschließt die reale Methode (im Falle, dass @classmethod
sie das zusätzliche Klassenargument übergibt). Die zugrunde liegende Methode ist immer noch vorhanden, versteckt, aber immer noch zugänglich .
Fußnote: Ich habe dies geschrieben, nachdem ein Namenskonflikt zwischen einer Klassen- und einer Instanzmethode meine Neugier geweckt hat. Ich bin weit entfernt von einem Python-Experten und hätte gerne Kommentare, wenn dies falsch ist.