Heim >Backend-Entwicklung >Python-Tutorial >Verstehen Sie die Verwendung von self in Python

Verstehen Sie die Verwendung von self in Python

高洛峰
高洛峰Original
2017-03-03 15:17:261623Durchsuche

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 &#39;__main__.Test&#39;>

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 &#39;__main__.Test&#39;>

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(&#39;self in Desc: %s &#39; % self )
    print(self, ins, cls)
class Test:
  x = Desc()
  def prt(self):
    print(&#39;self in Test: %s&#39; % self)
t = Test()
t.prt()
t.x
Die 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 &#39;__main__.Test&#39;>
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 &#39;__main__.Test&#39;>
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[&#39;name&#39;] = name 
  user[&#39;age&#39;] = age 
 
def set_user_name(user, x): 
  user[&#39;name&#39;] = x 
 
def set_user_age(user, x): 
  user[&#39;age&#39;] = x 
 
def get_user_name(user): 
  return user[&#39;name&#39;] 
 
def get_user_age(user): 
  return user[&#39;age&#39;] 
 
myself = {} 
user_init(myself,&#39;kzc&#39;,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(&#39;kzc&#39;,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.
  • Der Name von self ist nicht festgelegt, aber es ist am besten, self
  • wie vereinbart zu verwenden.
  • 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!


Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn