Ich las @ free_jinji2020s "Ich dachte darüber nach, warum Python selbst als Anfänger notwendig ist". Ich verfolgte einen anderen Ansatz, stellte mir die interne Struktur und die interne Funktionsweise des Python-Interpreters vor und überprüfte die Operation tatsächlich mit dem Python-Interpreter, was mein Verständnis vertiefte, sodass ich die Methode aufschreiben werde.
Darüber hinaus erfolgt die Funktionsprüfung mit der Python3-Serie. Bitte beachten Sie, dass das Anzeigeergebnis in der Python2-Serie unterschiedlich ist.
Wenn der Python-Interpreter das Python-Skript liest und die "def" -Definition findet, erstellt er eine "Instanz der" function "-Klasse, macht sie zu einem" Funktionsobjekt ", das den Prozess aufrufen kann, und weist sie der Variablen des Funktionsnamens zu. Die Verarbeitung in der Funktion wird in Bytecode kompiliert und dem Funktionsobjekt zugewiesen. Sie können den Bytecode auch in umgekehrter Reihenfolge zusammensetzen.
>>> def hello():
... print("Hello, world!")
...
>>> hello
<function hello at 0x6fffffd0dae8>
>>> type(hello)
<class'function'>
>>> hello()
Hello, world!
>>> hello.__code__.co_code.hex()
'740064018301010064005300'
>>> import dis
>>> dis.dis(hello)
2 0 LOAD_GLOBAL 0 (print)
2 LOAD_CONST 1 ('Hello, world!')
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
Wenn der Python-Interpreter die "Klassendefinition" findet, erstellt er eine Instanz der Klasse "type", macht sie zu einem "Klassenobjekt" und weist sie der Variablen des Klassennamens zu.
Ein Klassenobjekt kann einen ** Namespace ** (** Variablenraum **) erstellen, ** Variablen ** frei im Klassenobjekt definieren und ** Werte ** und ** Funktionen ** zuweisen. Ich werde.
Die Variablen im Objekt können mit der Funktion vars
angezeigt werden. Sie können die Namen auch im lokalen Bereich mit der Funktion dir
anzeigen. Ich habe auch verschiedene Informationen.
>>> class Sample:
... pass
...
>>> Sample.value = 123
>>> Sample.value * 3
369
>>> Sample.data = [1, 2, 3]
>>> vars(Sample)
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'Sample' objects>, '__weakref__': <attribute '__weakref__' of 'Sample' objects>, '__doc__': None,
'value': 123, 'data': [1, 2, 3]})
>>> dir(Sample)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']
>>> Sample.__name__
'Sample'
Die Funktion wird nur ausgeführt, wenn sie aufgerufen wird. Die Variablenzuweisung (Zuordnung zum Klassenobjekt) und die Funktionsdefinition (Zuordnung zum Funktionsobjekt), die direkt unter der Klassendefinition geschrieben wurden, werden jedoch zum Zeitpunkt der Klassendefinition ausgeführt.
>>> class Sample:
... value = 123
... print(value * 3)
...
369
>>> Sample.value
123
Wenn die class
-Definition eine def
-Definition (Funktionsdefinition) enthält, wird das "Funktionsobjekt" im Klassenobjekt zugewiesen.
Es kann mit class name.function name ()
aufgerufen werden.
>>> class Sample:
... def greet():
... print("Hey, guys!")
...
>>> Sample
<class'__main__.Sample'>
>>> type(Sample)
<class'type'>
>>> Sample.greet
<function Sample.greet at 0x6fffffd0dd08>
>>> type(Sample.greet)
<class'function'>
>>> Sample.greet()
Hey, guys!
Sie können sehen, dass das Funktionsobjekt "greet" ("function greet") der Variablen "greet" zugewiesen wurde.
>>> vars(Sample)
mappingproxy({'__module__': '__main__', 'greet': <function Sample.greet at 0x6fffffd0dd08>, '__dict__': <attribute '__dict__' of 'Sample' objects>, '__weakref__': <attribute '__weakref__' of 'Sample' objects>, '__doc__': None})
Beim Erstellen eines Klassenobjekts wird der Prozess "Konstruktor" automatisch als [__call__
-Methode] festgelegt (https://docs.python.org/ja/3.6/reference/datamodel.html#object.call) und" Sie können den Konstruktor jetzt mit dem Klassennamen () aufrufen.
Durch Aufrufen des Konstruktors wird ein "Datenbereich" erstellt, der als "Instanz" bezeichnet wird.
Instanzen können auch einen Namespace (Variablenraum) erstellen, Variablen frei definieren und Werte zuweisen. Die Anfangsinstanz ist ein leerer Zustand ohne Variablen.
>>> data = Sample()
>>> vars(data)
{}
>>> data.name = "Taro"
>>> vars(data)
{'name': 'Taro'}
Definieren wir eine "Funktion", die den der Instanz zugewiesenen "Namen" anzeigt und den "Namen" anzeigt. Sie benötigen ein Argument, das angibt, welche Instanz der Name ist.
>>> def introduce(data):
... print("My name is", data.name)
...
>>> introduce(data)
My name is Taro
Sie können die außerhalb der oben genannten Klasse definierte Funktion "Introduce" auch aufrufen, indem Sie sie einem Klassenobjekt zuweisen.
>>> introduce
<function introduce at 0x6fffffd0dc80>
>>> Sample.introduce = introduce
>>> Sample.introduce
<function introduce at 0x6fffffd0dc80>
>>> Sample.introduce(data)
My name is Taro
Der "Konstruktor" wurde beim Erstellen der Klasse automatisch festgelegt, die "Methode" wird jedoch beim Erstellen der Instanz automatisch festgelegt. Eine "Methode" ist eine Instanz der Methodenklasse. Es gibt verschiedene Arten von Methoden wie "Instanzmethode" und "Klassenmethode". Wenn Sie eine Methode aufrufen, wird die Funktion im Klassenobjekt mit der Instanz oder dem Klassenobjekt als erstem Argument aufgerufen.
>>> Sample.introduce
<function introduce at 0x6fffffd0dc80>
>>> type(Sample.introduce)
<class'function'>
>>> data.introduce
<bound method introduce of <__main__.Sample object at 0x6fffffd16518>>
>>> type(data.introduce)
<class'method'>
>>> data.introduce()
My name is Taro
Ich habe dem Klassenobjekt die außerhalb der Klasse definierte Funktion "Introduce" zugewiesen, aber es ist einfacher zu verstehen, ob die Funktionsdefinition innerhalb der Klasse geschrieben ist.
>>> class Person:
... def initialize(data, name):
... data.name = name
... def introduce(data):
... print("My name is", data.name)
...
>>> taro = Person()
>>> vars(taro)
{}
>>> Person.initialize(taro, "Taro")
>>> vars(taro)
{'name': 'Taro'}
>>> Person.introduce(taro)
My name is Taro
Sie können klasseninterne Funktionen auch über Instanzmethoden aufrufen. Wie ich zuvor geschrieben habe, ruft die Methode die Funktion im Klassenobjekt mit der Instanz selbst als erstem Argument auf.
>>> hanako = Person()
>>> hanako.inittialize("Hanako")
>>> hanako.introduce()
My name is Hanako
__init__
MethodeNach dem Erstellen der Instanz wird die Methode "initialize" aufgerufen, um den Namen festzulegen. Es wäre jedoch praktisch, wenn der Anfangswert im Argument des Konstruktors angegeben werden könnte.
Dies ist die Methode __init__
.
Nachdem der Konstruktor instanziiert hat, ruft er die Methode __init __ mit der Instanz selbst als erstem Argument auf. Mit den an den Konstruktor übergebenen Argumenten.
>>> class Person:
... def __init__(self, name):
... self.name = name
... def introduce(self):
... print("My name is", self.name)
...
>>> ichiro = Person("Ichiro")
>>> ichiro.introduce()
My name is Ichiro
In "PEP8: Python Code Style Guide" heißt es:
Verwenden Sie immer "self" als Namen des ersten Arguments der Instanzmethode. Verwenden Sie immer
cls
als Namen des ersten Arguments der Klassenmethode.
Es spielt keine Rolle, wie der Argumentname lautet, aber ändern wir den Argumentnamen "data" im obigen Code gemäß dem Styleguide in "self". Das ist die allgemeine Schreibweise.
@ classmethod
Wenn Sie beim Definieren einer In-Class-Funktion einen Dekorator "@ classmethod" hinzufügen, wird dieser durch eine Methode ersetzt, die das erste Argument als Klassenobjekt aufruft. Sie können die Verarbeitung für jede von der Instanz unabhängige Klasse definieren.
>>> class Sample:
... @classmethod
... def class_method(cls):
... print("called:", cls)
...
>>> Sample.class_method
<bound method Sample.class_method of <class'__main__.Sample'>>
>>> Sample.class_method()
called: <class'__main__.Sample'>
>>> s = Sample()
>>> s.class_method
<bound method Sample.class_method of <class'__main__.Sample'>>
>>> s.class_method()
called: <class'__main__.Sample'>
@ staticmethod
Wenn Sie beim Definieren einer In-Class-Funktion einen Dekorator "@ staticmethod" hinzufügen, wird die Funktion direkt aufgerufen, ohne das erste Argument hinzuzufügen. Es ist dasselbe wie eine normale Funktionsdefinition, aber wenn Sie es in den Klassennamensraum einfügen, können Sie eine Funktion mit demselben Namen in verschiedenen Klassen definieren, sodass Sie sich keine Gedanken über Namenskonflikte machen müssen.
>>> class Sample:
... @staticmethod
... def static_method():
... print("Hello, world!")
...
>>> Sample.static_method
<function Sample.static_method at 0x6fffffd1e268>
>>> Sample.static_method()
Hello, world!
>>> s = Sample()
>>> s.static_method
<function Sample.static_method at 0x6fffffd1e268>
>>> s.static_method()
Hello, world!
Die gesamte Verarbeitung in Python wird vom Funktionsobjekt ausgeführt, und ein Argument, das angibt, welche Daten = Instanz = zu verarbeitendes Objekt erforderlich sind, sowie die Operationsregel, dass der erste von der Instanz übergebene Argumentname mit "self" vereinheitlicht werden soll Wurde in PEP8 angegeben.
Ich habe den Quellcode des Python-Interpreters nicht eingehend verfolgt, daher denke ich, dass es einige Ungenauigkeiten gibt. Ich würde mich freuen, wenn Sie mir Kommentare wie Vorschläge geben könnten. Es gab viele Dinge, die ich verstehen konnte, wenn ich über die Gefühle des Python-Interpreters nachdachte. Warum denkst du nicht über die Gefühle des Python-Interpreters nach?
Recommended Posts