Heim >Backend-Entwicklung >Python-Tutorial >Verstehen Sie die Verwendung von self in Python
Als ich anfing zu lernen, wie man Klassen in Python schreibt, fand ich es sehr mühsam. Warum wird es beim Definieren benötigt, aber nicht beim Aufruf? Warum kann es nicht intern vereinfacht werden, um die Anzahl der Tastenanschläge zu reduzieren, die wir ausführen müssen? ? Nach der Lektüre dieses Artikels werden Sie alle Ihre Zweifel verstehen.
self stellt eine Instanz einer Klasse dar, keine Klasse.
Beispiel zur Veranschaulichung:
class Test: def prt(self): print(self) print(self.__class__) t = Test() t.prt()
Die Ausführungsergebnisse sind wie folgt
<__main__.Test object at 0x000000000284E080> <class '__main__.Test'>
Aus dem obigen Beispiel ist ersichtlich, dass self eine Instanz einer Klasse darstellt. Und self.class zeigt auf die Klasse.
self muss nicht als self geschrieben werden
Viele Kinder lernen zuerst andere Sprachen und dann Python, daher haben sie immer das Gefühl, dass self seltsam ist Du willst es so schreiben, kannst du?
Natürlich schreiben wir den obigen Code neu. Nachdem
class Test: def prt(this): print(this) print(this.__class__) t = Test() t.prt()
dahingehend geändert wurde, sind die Laufergebnisse genau die gleichen.
Natürlich ist es am besten, etablierte Gewohnheiten zu respektieren und sich selbst zu nutzen.
Kann ich nicht self schreiben?
Wenn wir im Python-Interpreter t.prt() aufrufen, interpretiert Python es tatsächlich als Test.prt(t). das heißt, self durch eine Instanz der Klasse ersetzen.
Interessierte Kinder können die Zeile t.prt() oben umschreiben, und die tatsächlichen Ergebnisse nach dem Ausführen sind genau die gleichen.
Tatsächlich wurde teilweise erklärt, dass self bei der Definition nicht weggelassen werden kann. Wenn Sie es unbedingt versuchen müssen, lesen Sie bitte unten:
class Test: def prt(): print(self) t = Test() t.prt()
Der Laufzeit-Erinnerungsfehler lautet wie folgt: prt hat bei der Definition keine Parameter, aber wir haben beim Ausführen zwangsweise einen Parameter übergeben.
Da t.prt() wie oben erklärt äquivalent zu Test.prt(t) ist, erinnert uns das Programm daran, dass wir einen weiteren Parameter t übergeben haben.
Traceback (most recent call last): File "h.py", line 6, in <module> t.prt() TypeError: prt() takes 0 positional arguments but 1 was given
Natürlich ist es in Ordnung, wenn wir beim Definieren und Aufrufen keine Klasseninstanz übergeben. Dies ist eine Klassenmethode.
class Test: def prt(): print(__class__) Test.prt()
Die laufenden Ergebnisse sind wie folgt
<class '__main__.Test'>
Beim Erben , pass Welche Instanz eingegeben wird, ist die übergebene Instanz, nicht die Instanz der Klasse, in der self definiert ist.
Schauen Sie sich zuerst den Code an
class Parent: def pprt(self): print(self) class Child(Parent): def cprt(self): print(self) c = Child() c.cprt() c.pprt() p = Parent() p.pprt()
Die laufenden Ergebnisse sind wie folgt
<__main__.Child object at 0x0000000002A47080> <__main__.Child object at 0x0000000002A47080> <__main__.Parent object at 0x0000000002A47240>
Erklärung:
Bei der Ausführung von c.cprt(), das sich auf eine Instanz der Child-Klasse bezieht, sollte es kein Verständnisproblem geben.
Aber wenn c.pprt() ausgeführt wird, entspricht es Child.pprt(c), sodass self immer noch auf eine Instanz der Child-Klasse verweist, da die pprt()-Methode nicht in self definiert ist. Die Vererbung wird vererbt. Wenn wir im Baum nachschlagen, stellen wir fest, dass die pprt()-Methode in der übergeordneten Klasse Parent definiert ist und daher erfolgreich aufgerufen wird.
In der Deskriptorklasse bezieht sich self auf die Instanz der Deskriptorklasse. Schauen wir uns zunächst das Beispiel an:
class Desc: def __get__(self, ins, cls): print('self in Desc: %s ' % self ) print(self, ins, cls) class Test: x = Desc() def prt(self): print('self in Test: %s' % self) t = Test() t.prt() t.xDie Laufergebnisse sind wie folgt:
self in Test: <__main__.Test object at 0x0000000002A570B8> self in Desc: <__main__.Desc object at 0x000000000283E208> <__main__.Desc object at 0x000000000283E208> <__main__.Test object at 0x0000000002A570B8> <class '__main__.Test'>Die meisten Kinderschuhe sind am Start Wenn Sie Fragen haben, warum gehören sie zur Kategorie Desc? Sollte das in nicht definierte Selbst die Instanz sein, die es aufruft? Wie wurde es zu einer Instanz der Desc-Klasse? Hinweis: Sie müssen Ihre Augen öffnen, um hier klar zu sehen, was t.x heißt, was bedeutet, dass es sich um das Attribut x der Instanz t der Testklasse handelt, da das Attribut x nicht in definiert ist In der Instanz t wird das Klassenattribut x gefunden. Dieses Attribut ist ein Deskriptorattribut, das eine Instanz der Desc-Klasse ist. Daher wird hier keine Testmethode verwendet. Wenn wir dann Attribut x direkt über die Klasse aufrufen, können wir das gleiche Ergebnis erzielen. Das Folgende ist das Ergebnis der Änderung von t.x in Test.x.
self in Test: <__main__.Test object at 0x00000000022570B8> self in Desc: <__main__.Desc object at 0x000000000223E208> <__main__.Desc object at 0x000000000223E208> None <class '__main__.Test'>Exkurs: Da die Deskriptorklasse in vielen Fällen immer noch wissen muss, wer die Instanz ist, die den Deskriptor aufruft, gibt es in der Deskriptorklasse eine Der zweite Parameter ins wird verwendet, um die Klasseninstanz darzustellen, die ihn aufruft. Wenn also t. Beim Aufruf mit Test.x wird None zurückgegeben, da keine Instanz vorhanden ist.
Selbst in Python anhand der Essenz von OO verstehen
Angenommen, ich möchte beispielsweise mit den Daten des Benutzers arbeiten, die Name und Alter enthalten. Wenn prozessorientiert verwendet wird, sieht die Implementierung wie folgt aus.
def user_init(user,name,age): user['name'] = name user['age'] = age def set_user_name(user, x): user['name'] = x def set_user_age(user, x): user['age'] = x def get_user_name(user): return user['name'] def get_user_age(user): return user['age'] myself = {} user_init(myself,'kzc',17) print get_user_age(myself) set_user_age(myself,20) print get_user_age(myself)Wie Sie sehen, müssen Benutzerparameter für verschiedene Vorgänge am Benutzer übergeben werden.
Wenn Sie objektorientiert verwenden, müssen Sie die Benutzerparameter nicht jedes Mal hin und her übergeben. Die relevanten Daten und Operationen sind an einer Stelle gebunden. Daten können problemlos von verschiedenen Stellen in dieser Klasse abgerufen werden.
Der Grund, warum auf Daten von verschiedenen Stellen in der Klasse aus zugegriffen werden kann, besteht darin, dass sie an self gebunden sind. Natürlich muss der erste Parameter seiner Methode nicht self genannt werden, sondern kann auch als anderer Name bezeichnet werden nur eine Konvention.Das Folgende ist die objektorientierte Implementierung. Sie sehen, dass sie viel strukturierter, klarer und lesbarer ist.
class User(object): def __init__(self,name,age): self.name = name self.age = age def SetName(self,name): self.name = name def SetAge(self,age): self.age = age def GetName(self): return self.name def GetAge(self): return self.age u = User('kzc',17) print u.GetName() print u.GetAge()Wie Sie am obigen Beispiel sehen können, ist objektorientiert eigentlich recht nützlich, aber die meisten Leute abstrahieren es nicht gut und kapseln es nicht Na ja, falsche Anwendung.
Zusammenfassung
Selbst muss beim Definieren definiert werden, wird aber beim Aufruf automatisch übergeben.
self bezieht sich beim Aufruf immer auf die Instanz der Klasse.
Weitere Artikel zum Verständnis der Verwendung von self in Python finden Sie auf der chinesischen PHP-Website!