[PYTHON] Ich habe die Implementierung von range gelesen (Objects / rangeobject.c)

Da ich mir im letzten Jahr Sorgen um "Python-ness" gemacht hatte, las ich die Implementierung von "range".

Verwenden wir "xrange" anstelle von "range"! Es war eine super Entgleisung aus der Geschichte der Python 2-Ära.

Über CPython

Repository: https://hg.python.org/cpython Spiegeln: https://github.com/python/cpython (Ich bin mir bei Mercurial nicht sicher, daher sind alle folgenden Git)

https://github.com/python/cpython/tree/master/Objects Es gibt verschiedene interessante Dinge in der Linie. Alle von ihnen sind lang und unlesbar.

Source files for various builtin objects

Über die Reichweite

Es scheint, dass es eine Geschichte gab, in der range und xrange in Python2 unterschiedlich sind. Es scheint, dass Python 3 sich darüber keine Sorgen machen muss. Es scheint, dass es etwas gibt, das [2to3] heißt (http://docs.python.jp/3.5/library/2to3.html), und es gibt auch ein Programm, das "xrange" ordnungsgemäß in "range" konvertiert. https://github.com/python/cpython/blob/master/Lib/lib2to3/fixes/fix_xrange.py

Diesmal https://github.com/python/cpython/blob/28b093620c3ae9be02449ea0cecd8b4d649c80d2/Objects/rangeobject.c Ich lese. Es gibt 1246 Zeilen, aber der Schwierigkeitsgrad ist wahrscheinlich niedrig.

Lass es uns versuchen

3〜4: include

Die Header-Datei ist https://github.com/python/cpython/tree/master/Include Es ist in.

Was in rangeobject.c zu lesen ist

Zwei von. Das Array von PyMemberDef scheint die Namen, Typen und Offsets der Mitglieder der C-Struktur zu definieren.

rangeobject

6〜19: struct rangeobject

Das Strukturbereichsobjekt

haben. Es sieht aus wie eine Reichweite. PyObject_HEAD und PyObject werden in Common Object Structures und allen Objekttypen beschrieben Ist eine Erweiterung von PyObject.

Der Wert PY_SSIZE_T_MAX wird im Kommentar angezeigt. Py_ssize_t ist eine vorzeichenbehaftete Ganzzahl im Gegensatz zu ssize_t. ssize_t wird in PEP 353 - Verwenden von ssize_t als Indextyp | Python.org erwähnt.

21〜39: validate_step(PyObject *step)

Hilfsfunktion für Verifizierungsschritt. Schritt 0 ist nicht als Bereich geeignet, daher scheint er ihn zu überprüfen. Wenn kein Schritt angegeben ist, wird er als 1 betrachtet.

41〜42: compute_range_length(PyObject *start, PyObject *stop, PyObject *step)

→ Zeile 151

44〜64: make_range_object(PyTypeObject *type, PyObject *start, PyObject *stop, PyObject *step)

Erstellen Sie aus dem Argument ein Bereichsobjekt. Es ist das folgende range_new, das wirklich rangeobject erstellt, und wenn es kein Problem gibt, nachdem verschiedene Dinge mit range_new überprüft wurden, wird make_range_object aufgerufen. Da rangeobject ein Objekt ist, ist es eine Erweiterung von PyObject. Geben Sie nach dem Erstellen von "PyObject" den Wert des Bereichs (Start usw.) an.

Was ist PyObject_New (Typ, Typobj)? (Typ *) _PyObject_New (Typobj)? -L135), wodurch "PyObject" durch Zuweisen von Speicher erstellt wird. Weitere Informationen finden Sie unter object.c. Abkürzung.

66〜129: range_new(PyTypeObject *type, PyObject *args, PyObject *kw)

Machen Sie verschiedene Überprüfungen richtig und machen Sie "RangeObject". Wenn ein unangemessener Wert übergeben wird, geben Sie die Erstellung auf, weisen Sie den zugewiesenen Speicher zu und geben Sie "NULL" zurück. Es gab einen Kommentar wie diesen.

/* XXX(nnorwitz): should we error check if the user passes any empty ranges?
   range(-10)
   range(0, -5)
   range(0, 5, -1)
*/

131〜139: PyDoc

Dokumente für Bereich (Stopp) und Bereich (Start, Stopp [, Schritt]) werden mit einem Makro namens PyDoc_STRVAR geschrieben. PyDoc_STRVAR

#define PyDoc_VAR(name) static char name[]

Ankommen in. Es ist ein Makro für Inline-Dokumente.

141〜149: range_dealloc(rangeobject *r)

Freigabe von Mitgliedern von struct rangeobject → Freigabe von Struktur.

151〜227: compute_range_length(PyObject *start, PyObject *stop, PyObject *step)

Berechnet die Anzahl der Elemente im Bereich (lo, hi, step) und gibt sie zurück. Der Algorithmus scheint der gleiche zu sein wie get_len_of_range (lo, hi, step) ab Zeile 865, und die detaillierte Geschichte ist dort geschrieben. Der Unterschied besteht darin, dass das Argument "PyObject" ist und dass "PyObject" als "PyLong" angesehen wird und die Geschichte weitergeht.

229〜233: range_length(rangeobject *r)

Gibt die Elementlänge als Py_ssize_t zurück. Das hier verwendete PyLong_AsSsize_t scheint "Py_ssize_t" von einem Objekt vom Typ int zurückzugeben.

235〜248: compute_item(rangeobject *r, PyObject *i)

Berechnen Sie den Wert von Anfang, i und Schritt und erhalten Sie den nächsten Wert. Der Kommentar sagt auch "return r-> start + (i * r-> step)". Wie es ist.

250〜307: compute_range_item(rangeobject *r, PyObject *arg)

Diejenigen, die das obige compute_item aufrufen. Vorher wird i von compute_item (rangeobject * r, PyObject * i) von arg ausgegeben (tatsächlich scheint es "PyLong" zu sein) und der Bereich wird überprüft.

309〜319: range_item(rangeobject *r, Py_ssize_t i)

Die Seite, die das obige compute_range_item aufruft. Dies kümmert sich um Funktionsargumente und Referenzen.

321〜358: compute_slice(rangeobject *r, PyObject *_slice)

Machen Sie ein Stück "RangeObject". Es behandelt auch Fehler und gibt Referenzen frei.

360〜409: range_contains_long(rangeobject *r, PyObject *ob)

In den nächsten range_contains, range_index, range_count

PyLong_CheckExact(ob) || PyBool_Check(ob)

Wird mit dem Häkchen ausgeführt. PyLong_CheckExact und PyBool_Check /boolobject.h#L12) ist auch ein Makro, das eine Typprüfung mit derselben Bedeutung durchführt.

Liegt der Inhalt einfach innerhalb des vom Bereichsobjekt angegebenen Bereichs (= existiert er)?

411〜419: range_contains(rangeobject *r, PyObject *ob)

(PyLong_CheckExact(ob) || PyBool_Check(ob))Dann der obige Bereich_contains_Andernfalls lange verwenden_PySequence_IterSearchMachen Sie ein Urteil mit.

421〜465: range_equals(rangeobject *r0, rangeobject *r1)

Eine Funktion, die zwei Range-Objekte vergleicht. In einem Kommentar wird erläutert, wo gesucht werden muss, um eine Entscheidung zu treffen.

/*
   if r0 is r1:
       return True
   if len(r0) != len(r1):
       return False
   if not len(r0):
       return True
   if r0.start != r1.start:
       return False
   if len(r0) == 1:
       return True
   return r0.step == r1.step
*/

467〜495: range_richcompare(PyObject *self, PyObject *other, int op)

Das Argument lautet "PyObject", aber es gibt eine Überprüfung, um festzustellen, ob andere "PyRange_Type" ist. op verweist auf den Vergleichsoperator (https://github.com/python/cpython/blob/28b093620c3ae9be02449ea0cecd8b4d649c80d2/Include/object.h#L927), und diese Funktion zielt auf "Py_NE" und "Py_EQ" ab nur.

Rufen Sie schließlich range_equals auf.

497〜550: range_hash(rangeobject *r)

Hash-Funktion für rangeobject. Kehren Sie mit dem Typ [Py_hash_t] zurück (https://github.com/python/cpython/blob/28b093620c3ae9be02449ea0cecd8b4d649c80d2/Include/pyport.h#L93). Die Werte, die zum Abrufen des Hashs verwendet werden, sind len (), start und step. Die Verarbeitung wird entsprechend dem Wert von len (r) geändert.

/* Hash function for range objects.  Rough C equivalent of

   if not len(r):
       return hash((len(r), None, None))
   if len(r) == 1:
       return hash((len(r), r.start, None))
   return hash((len(r), r.start, r.step))
*/

552〜570: range_count(rangeobject *r, PyObject *ob)

PyLong_CheckExact(ob) || PyBool_Check(ob)Zum Zeitpunkt der Reichweite_contains_sonst lang_PySequence_Zählen Sie mit IterSearch.

572〜602: range_index(rangeobject *r, PyObject *ob)

PyLong_CheckExact(ob) || PyBool_Check(ob)Zum Zeitpunkt der Reichweite_contains_sonst lang_PySequence_Suchen Sie mit IterSearch. Für range_contains_long nach Überprüfung auf Existenz

idx = PyNumber_FloorDivide(tmp, r->step);

Der Standort wird berechnet und gelöscht.

604〜613: range_as_sequence

Registrieren Sie verschiedene Funktionen gemäß PySequenceMethods. Hier

PySequenceMethods range_as_sequence
lenfunc sq_length range_Länge → Zeile 229
ssizeargfunc sq_item range_Punkt → Zeile 309
objobjproc sq_contains range_enthält → Zeile 411

Nur sind registriert.

615〜633: range_repr(rangeobject *r)

Geben Sie die Ausgabezeichenfolge in PyUnicode aus. Wenn Schritt 1 ist, wird Schritt weggelassen.

635〜641: range_reduce(rangeobject *r, PyObject *args)

Es scheint eine Hilfsfunktion von [pickle] zu sein (https://docs.python.org/3.6/library/pickle.html). Py_BuildValue ([\ _Py_BuildValue_Size/p). Geben Sie die Informationen zu struct rangeobject an Python / modsupport.c # L441-L450)).

643〜662: range_subscript(rangeobject* self, PyObject* item)

Artikel ist Wenn Sie PyIndex_Check durchgehen (kurz, int), können Sie comp_ verwenden. Wenn Sie PySlice_Check durchgehen (im Wesentlichen Slice), können Sie compute_slice verwenden. Gibt das Element zurück. Ansonsten ist es ein Fehler.

665〜669: range_as_mapping

Dieses Mal wird es gemäß PyMappingMethods registriert. 2 von 3 Funktionen sind implementiert.

PyMappingMethods range_as_mapping
lenfunc mp_length range_Länge → Zeile 229
binaryfunc mp_subscript range_Index → Zeile 643

671: range_iter(PyObject *seq)

→ Zeile 1076

672: range_reverse

→ Zeile 1134

674〜682: PyDoc

Dokumente für Reverse, Count und Index.

684〜690: range_methods

PyMethodDef verknüpft Funktionen in Python mit in C implementierten Funktionen, Argumentinformationen und Dokumentation. Ding.

Hier sind folgende Funktionen verknüpft.

Eingebaut Implementierung in C.
__reversed__ range_reverse →1134
__reduce__ range_reduce →635
count range_count →552
index range_index →572

692〜697: range_members

PyMemberDef repräsentiert den Namen, den Typ und den Versatz der Mitglieder der C-Struktur. Hier handelt es sich um eine Reihe von Start-, Stopp- und Schrittinformationen.

699〜738: PyRange_Type

Eine Typdefinition namens "PyRange_Type". Es gibt verschiedene Einstellungselemente, aber im Fall des Bereichs werden die folgenden Informationen registriert Es gibt.

PyTypeObject PyRange_Type
const char *tp_name "range"
Py_ssize_t tp_basicsize sizeof(rangeobject)
destructor tp_dealloc (destructor)range_dealloc →141
reprfunc tp_repr (reprfunc)range_repr →615
PySequenceMethods *tp_as_sequence &range_as_sequence →604
PyMappingMethods *tp_as_mapping &range_as_mapping →665
hashfunc tp_hash (hashfunc)range_hash →497
getattrofunc tp_getattro PyObject_GenericGetAttr
unsigned long tp_flags Py_TPFLAGS_DEFAULT
const char *tp_doc range_doc
richcmpfunc tp_richcompare range_richcompare →467
getiterfunc tp_iter range_iter →1076
struct PyMethodDef *tp_methods range_methods →684
struct PyMemberDef *tp_members range_members →692
newfunc tp_new range_new →66

Übrigens scheint PyVarObject_HEAD_INIT mit der Definition des ursprünglichen Segments von "Py" in Zusammenhang zu stehen.

rangeiterobject

740〜753: struct rangeiterobject

Die Definition ähnelt "rangeobject", unterscheidet sich jedoch geringfügig.

755〜764: rangeiter_next(rangeiterobject *r)

Holen Sie sich den nächsten Wert, indem Sie zum Starten den Schritt index * hinzufügen. Um einen Überlauf zu vermeiden, wird es in unsigniert umgewandelt und zurückgegeben.

766〜770: rangeiter_len(rangeiterobject *r)

Berechnen Sie die Länge mit len --index.

772〜773: PyDoc

length_hint_doc. Es scheint eine private Methode zu sein, die eine Schätzung der Länge der Liste liefert.

775〜802: rangeiter_reduce(rangeiterobject *r)

Funktion für Gurke. Es dauert länger als das Bereichsobjekt, da eine Konvertierung in "PyLong" erfolgt.

804〜817: rangeiter_setstate(rangeiterobject *r, PyObject *state)

Stellen Sie den Wert im Index ein.

819〜820: PyDoc

doc für reduzieren und setstate. Beide scheinen mit Gurken zu tun zu haben.

822〜830: rangeiter_methods

Eingebaut Implementierung in C.
__length_hint__ rangeiter_len →766
__reduce__ rangeiter_reduce →775
__setstate__ rangeiter_setstate → 804

832〜863: PyRangeIter_Type

PyTypeObject PyRangeIter_Type
const char *tp_name "range_iterator"
Py_ssize_t tp_basicsize sizeof(rangeiterobject)
destructor tp_dealloc (destructor)PyObject_Del
getattrofunc tp_getattro PyObject_GenericGetAttr
unsigned long tp_flags Py_TPFLAGS_DEFAULT
getiterfunc tp_iter PyObject_SelfIter
iternextfunc tp_iternext (iternextfunc)rangeiter_next →755
struct PyMethodDef *tp_methods rangeiter_methods →822

Ich frage mich, warum es PyObject_Del und PyObject_DEL gibt ...

865〜891: get_len_of_range(long lo, long hi, long step)

Gibt die Anzahl der Elemente im Bereich zurück (lo, hi, step).

    /* -------------------------------------------------------------
    If step > 0 and lo >= hi, or step < 0 and lo <= hi, the range is empty.
    Else for step > 0, if n values are in the range, the last one is
    lo + (n-1)*step, which must be <= hi-1.  Rearranging,
    n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives
    the proper value.  Since lo < hi in this case, hi-lo-1 >= 0, so
    the RHS is non-negative and so truncation is the same as the
    floor.  Letting M be the largest positive long, the worst case
    for the RHS numerator is hi=M, lo=-M-1, and then
    hi-lo-1 = M-(-M-1)-1 = 2*M.  Therefore unsigned long has enough
    precision to compute the RHS exactly.  The analysis for step < 0
    is similar.
    ---------------------------------------------------------------*/

Die Kommentarbeschreibung ist länger als der Code. Der Punkt teilt nur den Abschnitt durch die Anzahl der Schritte.

893〜915: fast_range_iter(long start, long stop, long step)

Machen Sie einen Entfernungsmesser. Wenn es länger als der lange Typ von C ist, wird NULL als Fehler zurückgegeben.

longrangeiterobject

917〜923: struct longrangeiterobject

Dies ist "PyObject".

925〜929: longrangeiter_len(longrangeiterobject *r, PyObject *no_args)

Verwenden Sie PyNumber_Subtract, um den Index von len zu subtrahieren.

931〜958: longrangeiter_reduce(longrangeiterobject *r)

Für Gurke. Berechnen Sie stop und berechnen Sie den Wert, indem Sie mit make_range_object ein Bereichsobjekt erstellen.

960〜987: longrangeiter_setstate(longrangeiterobject *r, PyObject *state)

Status in Index setzen.

989〜997: longrangeiter_methods

Eingebaut Implementierung in C.
__length_hint__ longrangeiter_len →925
__reduce__ longrangeiter_reduce →931
__setstate__ longrangeiter_setstate → 960

999〜1007: longrangeiter_dealloc(longrangeiterobject *r)

Referenzen werden in der Reihenfolge von struct member → longrangeiterobject gelöscht.

1009〜1041: longrangeiter_next(longrangeiterobject *r)

Schließlich wird es durch Hinzufügen von Schritt * Index berechnet, um zu beginnen.

1043〜1074: PyLongRangeIter_Type

PyTypeObject PyRangeIter_Type
const char *tp_name "longrange_iterator"
Py_ssize_t tp_basicsize sizeof(longrangeiterobject)
destructor tp_dealloc (destructor)longrangeiter_dealloc →999
getattrofunc tp_getattro PyObject_GenericGetAttr
unsigned long tp_flags Py_TPFLAGS_DEFAULT
getiterfunc tp_iter PyObject_SelfIter
iternextfunc tp_iternext (iternextfunc)longrangeiter_next →1009
struct PyMethodDef *tp_methods longrangeiter_methods →989

Iter-Generierung

1076〜1132: range_iter(PyObject *seq)

Es gibt ein Muster, um einen Rangeiter aus rangeobject seq zu machen, und ein Muster, um einen Longrangeiter zu machen. Die Grenze ist, ob Start, Stopp und Bereich durch den Typ C long dargestellt werden können.

1134〜1246: range_reverse(PyObject *seq)

Dies wird auch überprüft, um festzustellen, ob es in eine lange passt. Da es umgekehrt ist, muss step auch -step überprüfen. Der Rest wird durch Ersetzen von Start und Stopp gut erzeugt.

Impressionen

Es war eine lange Zeit, aber ich habe das Gefühl, die Atmosphäre von CPython irgendwie verstanden zu haben. Ich habe zum ersten Mal eine anständige C-Sprache gelesen und gelernt. (Ich habe gerade Shoboi C als Verfahrenssprache an der Universität gemacht)

Wie ist es also mit Python? Das Gefühl von Python ist schwierig.

Recommended Posts

Ich habe die Implementierung von range gelesen (Objects / rangeobject.c)
Lesen Sie die Implementierung des globalen ARM-Timers
Ich habe die Varianten von UKR gelesen und implementiert
Ich verfolgte die Implementierung des Befehls du (erste Hälfte)
Ich verfolgte die Implementierung des Befehls du (zweite Hälfte)
Ich habe SHAPs Zeitung gelesen
Ich habe den Mechanismus der Flaschenanmeldung untersucht!
Ich möchte die HTML-Version der OpenCV 3.1-Version "OpenCV-Python Tutorials" lesen
[Python] Ich habe die Theorie und Implementierung der logistischen Regression gründlich erklärt
[Python] Ich habe die Theorie und Implementierung des Entscheidungsbaums gründlich erklärt
Ich brachte AI dazu, über die Texte von Genshi Yonezu nachzudenken (Implementierung)
Ich habe versucht, die häufig verwendete Implementierungsmethode von pytest-mock zusammenzufassen
Ich habe die Optionen von copyMakeBorder von OpenCV überprüft
Othello-Aus der dritten Zeile von "Implementation Deep Learning" (3)
Die Ordnerstruktur von Flask ist zusammengefasst
Ich kannte die Grundlagen von Python nicht
Ich sehe, ich werde den UNIX-Prozess lesen
Die Python-Projektvorlage, an die ich denke.
Lesen Sie den gesamten Inhalt von proc / [pid]
Othello-Aus der dritten Zeile von "Implementation Deep Learning" (2)
[Python] Ich habe die Theorie und Implementierung der Support Vector Machine (SVM) ausführlich erklärt.
[Python] Lesen Sie den Quellcode von Flasche Teil 2
Ich habe versucht, die Wetterkarte einer Clusteranalyse zu unterziehen
Ich habe das tiefste Problem von Hiroshi Yuki gelöst.
Warum die Python-Implementierung von ISUCON 5 Bottle verwendet
Organisieren Sie die Bedeutung von Methoden, Klassen und Objekten
Angeben des Bereichs von Ruby- und Python-Arrays
Ich habe die Liste der Tastenkombinationen von Jupyter überprüft
Ich habe versucht, die Trapezform des Bildes zu korrigieren
Lesen Sie die Ausgabe von subprocess.Popen in Echtzeit
[Python] Lesen Sie den Quellcode von Flasche Teil 1
Probieren Sie Progate Free Edition [Python I]
Ich habe die Sitzungsaufbewahrungsdauer von Django überprüft
Ich habe die Verarbeitungsgeschwindigkeit der numpy eindimensionalisierung überprüft
Ich habe einige der neuen Funktionen von Python 3.8 touched angesprochen
Ich möchte das Erscheinungsbild von zabbix anpassen
Ich habe versucht, den Bildfilter von OpenCV zu verwenden
Ich habe versucht, die Texte von Hinatazaka 46 zu vektorisieren!
Ich habe versucht, Objekte aus dem Bild des Steak-Sets zu sortieren
Ich habe mir den Inhalt von sklearn (scikit-learn) angesehen. (1) ~ Was ist mit der Implementierung von CountVectorizer? ~
[Rezept des Trainers] Ich habe die Flasche des Python-Frameworks berührt.
Vorlage des Python-Skripts zum Lesen des Inhalts der Datei
Ich möchte das Ausführungsergebnis von strace erfassen
Spielen Sie mit der Implementierung der Pythonista 3-Benutzeroberfläche [Super Super Primer]
Ich habe versucht, die Grundform von GPLVM zusammenzufassen
Ich habe das MNIST-Tutorial von tensorflow für Anfänger ausprobiert.
Das Ende der katastrophalen Programmierung # 04 "Fehlerhafter Ausnahmebereich"
Ich verglich die Identität der Bilder nach Hu Moment
Vielleicht habe ich die Auswirkungen von Shell Shock auf CGI überschätzt
Visualisieren Sie den Bereich der internen und externen Einfügungen mit Python
Python-Implementierung der Bayes'schen linearen Regressionsklasse
Über das Testen bei der Implementierung von Modellen für maschinelles Lernen
Ich habe die Ausgabespezifikationen von Bidirectional LSTM von PyTorch überprüft
Ich habe mir die Versionen von Blender und Python angesehen
Ich möchte die Grundlagen von Bokeh vollständig verstehen
Die Leistung von PHP war besser als ich erwartet hatte