PEP 237 – Vereinheitlichung von langen und ganzen Zahlen
- Autor:
- Moshe Zadka, Guido van Rossum
- Status:
- Final
- Typ:
- Standards Track
- Erstellt:
- 11. März 2001
- Python-Version:
- 2.2
- Post-History:
- 16. Mrz 2001, 14. Aug 2001, 23. Aug 2001
Zusammenfassung
Python unterscheidet derzeit zwischen zwei Arten von ganzen Zahlen (ints): reguläre oder kurze ints, die durch die Größe eines C-long begrenzt sind (typischerweise 32 oder 64 Bit), und lange ints, die nur durch den verfügbaren Speicher begrenzt sind. Wenn Operationen mit kurzen ints Ergebnisse liefern, die nicht in ein C-long passen, lösen sie einen Fehler aus. Es gibt auch einige andere Unterschiede. Dieses PEP schlägt vor, die meisten Unterschiede in der Semantik abzuschaffen und die beiden Typen aus der Perspektive des Python-Benutzers zu vereinheitlichen.
Begründung
Viele Programme stellen fest, dass sie nachträglich mit größeren Zahlen umgehen müssen, und die Änderung von Algorithmen ist später umständlich. Dies kann die Leistung im Normalfall beeinträchtigen, wenn die gesamte Arithmetik mit langen ints durchgeführt wird, unabhängig davon, ob sie benötigt werden oder nicht.
Die Prozesswortgröße, die in der Sprache exponiert wird, beeinträchtigt die Portabilität. Beispielsweise sind Python-Quellcodedateien und .pyc-Dateien aufgrund dessen nicht zwischen 32-Bit- und 64-Bit-Maschinen portierbar.
Es gibt auch den allgemeinen Wunsch, unnötige Details vor dem Python-Benutzer zu verbergen, wenn sie für die meisten Anwendungen irrelevant sind. Ein Beispiel ist die Speicherzuweisung, die in C explizit, in Python aber automatisch erfolgt, was uns den Komfort von unbegrenzten Größen für Zeichenketten, Listen usw. bietet. Es ist sinnvoll, diesen Komfort auf Zahlen auszudehnen.
Neue Python-Programmierer (egal ob sie neu in der Programmierung im Allgemeinen sind oder nicht) haben eine Sache weniger zu lernen, bevor sie mit der Verwendung der Sprache beginnen können.
Implementierung
Ursprünglich wurden zwei alternative Implementierungen vorgeschlagen (eine von jedem Autor)
- Das Feld für ein C-long des Typs
PyIntwird in einunion { long i; struct { unsigned long length; digit digits[1]; } bignum; };
Nur die
n-1niederwertigsten Bits deslonghaben eine Bedeutung; das oberste Bit ist immer gesetzt. Dies unterscheidet dieunion. AllePyInt-Funktionen überprüfen dieses Bit, bevor sie entscheiden, welche Arten von Operationen verwendet werden sollen. - Die bestehenden Typen für kurze und lange ints bleiben bestehen, aber Operationen geben einen langen int zurück, anstatt
OverflowErrorauszulösen, wenn ein Ergebnis nicht als kurzer int dargestellt werden kann. Ein neuer Typ,integer, kann eingeführt werden, der ein abstrakter Basistyp ist, von dem sowohl derintals auch derlongImplementierungstyp abgeleitet sind. Dies ist nützlich, damit Programme die Integer-Eigenschaft mit einem einzigen Test überprüfen könnenif isinstance(i, integer): ...
Nach einiger Überlegung wurde der zweite Implementierungsplan ausgewählt, da er wesentlich einfacher zu implementieren ist, auf der C-API-Ebene abwärtskompatibel ist und zusätzlich teilweise als Übergangsmaßnahme implementiert werden kann.
Inkompatibilitäten
Die folgenden Operationen haben (meist subtil) unterschiedliche Semantiken für kurze und lange Integer, und eine oder die andere muss irgendwie geändert werden. Dies soll eine erschöpfende Liste sein. Wenn Sie von einer anderen Operation wissen, die je nachdem, ob ein kurzer oder ein langer Integer mit demselben Wert übergeben wird, ein anderes Ergebnis liefert, schreiben Sie bitte an den zweiten Autor.
- Derzeit lösen alle arithmetischen Operatoren für kurze ints mit Ausnahme von
<<einenOverflowErroraus, wenn das Ergebnis nicht als kurzer int dargestellt werden kann. Dies wird geändert, um stattdessen einen langen int zurückzugeben. Die folgenden Operatoren können derzeitOverflowErrorauslösen:x+y,x-y,x*y,x**y,divmod(x, y),x/y,x%yund-x. (Die letzten vier können nur überlaufen, wenn der Wert-sys.maxint-1involviert ist.) - Derzeit kann
x<<nBits für kurze ints verlieren. Dies wird geändert, um einen langen int zurückzugeben, der alle verschobenen Bits enthält, wenn das Zurückgeben eines kurzen ints Bits verlieren würde (wobei ein Vorzeichenwechsel als Sonderfall des Verlusts von Bits betrachtet wird). - Derzeit können hexadezimale und oktale Literale für kurze ints negative Werte angeben; zum Beispiel
0xffffffff == -1auf einer 32-Bit-Maschine. Dies wird geändert, um0xffffffffL(2**32-1) zu entsprechen. - Derzeit verhalten sich die String-Formatierungsoperatoren
%u,%x,%Xund%osowie die eingebauten Funktionenhex()undoct()für negative Zahlen unterschiedlich: negative kurze ints werden als vorzeichenlose C-long formatiert, während negative lange ints mit einem Minuszeichen formatiert werden. Dies wird geändert, um in allen Fällen die Semantik von langen ints zu verwenden (aber ohne das nachgestellte L, das derzeit die Ausgabe vonhex()undoct()für lange ints kennzeichnet). Beachten Sie, dass dies bedeutet, dass%uzu einem Alias für%dwird. Es wird schließlich entfernt. - Derzeit gibt die
repr()eines langen ints eine Zeichenkette zurück, die mit L endet, während dierepr()eines kurzen ints dies nicht tut. Das L wird entfernt; aber nicht vor Python 3.0. - Derzeit gibt eine Operation mit langen Operanden niemals einen kurzen int zurück. Dies *kann* sich ändern, da es einige Optimierungen ermöglicht. (In diesem Bereich wurden bisher keine Änderungen vorgenommen, und es sind auch keine geplant.)
- Der Ausdruck
type(x).__name__hängt davon ab, ob x ein kurzer oder ein langer int ist. Da die Implementierungsalternative 2 gewählt wird, bleibt dieser Unterschied bestehen. (In Python 3.0 können wir *vielleicht* einen Trick anwenden, um den Unterschied zu verbergen, da es ärgerlich ist, den Unterschied für Benutzercode offenzulegen, und noch mehr, da der Unterschied zwischen den beiden Typen weniger sichtbar ist.) - Lange und kurze ints werden vom
marshal-Modul sowie von den ModulenpickleundcPickleunterschiedlich behandelt. Dieser Unterschied bleibt bestehen (zumindest bis Python 3.0). - Kurze ints mit kleinen Werten (typischerweise zwischen -1 und 99 einschließlich) werden *interniert* – wann immer ein Ergebnis einen solchen Wert hat, wird ein vorhandener kurzer int mit demselben Wert zurückgegeben. Dies geschieht nicht für lange ints mit denselben Werten. Dieser Unterschied bleibt bestehen. (Da es keine Garantie für diese Internierung gibt, ist es fraglich, ob dies ein semantischer Unterschied ist – aber es kann Code existieren, der
isfür Vergleiche von kurzen ints verwendet und aufgrund dieser Internierung zufällig funktioniert. Solcher Code kann fehlschlagen, wenn er mit langen ints verwendet wird.)
Literale
Ein nachgestelltes L am Ende eines Ganzzahlliterals hat keine Bedeutung mehr und wird schließlich illegal. Der Compiler wählt den geeigneten Typ ausschließlich basierend auf dem Wert. (Bis Python 3.0 erzwingt es, dass das Literal ein langer int ist; aber Literale ohne nachgestelltes L können ebenfalls lange ints sein, wenn sie nicht als kurze ints dargestellt werden können.)
Eingebaute Funktionen
Die Funktion int() gibt je nach Wert des Arguments einen kurzen oder einen langen int zurück. In Python 3.0 ruft die Funktion long() die Funktion int() auf; vorher wird sie weiterhin das Ergebnis auf einen langen int erzwingen, aber ansonsten genauso funktionieren wie int(). Der eingebaute Name long bleibt in der Sprache erhalten, um den langen Implementierungstyp darzustellen (sofern er in Python 3.0 nicht vollständig eliminiert wird), aber die Verwendung der Funktion int() wird weiterhin empfohlen, da sie bei Bedarf automatisch einen langen int zurückgibt.
C API
Die C-API bleibt unverändert; C-Code muss sich weiterhin der Unterscheidung zwischen kurzen und langen ints bewusst sein. (Die C-API von Python 3.0 wird wahrscheinlich völlig inkompatibel sein.)
Die PyArg_Parse*() APIs akzeptieren bereits lange ints, solange sie sich im Bereich von C-ints oder longs befinden, sodass Funktionen, die C-int- oder long-Argumente entgegennehmen, sich keine Gedanken über die Verarbeitung von Python-longs machen müssen.
Übergang
Es gibt drei Hauptphasen für die Umstellung
- Kurze Int-Operationen, die derzeit
OverflowErrorauslösen, geben stattdessen einen langen Int-Wert zurück. Dies ist die einzige Änderung in dieser Phase. Literale werden weiterhin zwischen kurzen und langen ints unterscheiden. Die anderen aufgelisteten semantischen Unterschiede (einschließlich des Verhaltens von<<) bleiben bestehen. Da diese Phase nur Situationen ändert, die derzeitOverflowErrorauslösen, wird angenommen, dass dies keinen bestehenden Code bricht. (Code, der von dieser Ausnahme abhängt, wäre zu kompliziert, um sich darum zu kümmern.) Für diejenigen, die sich um extreme Abwärtskompatibilität sorgen, ermöglicht eine Befehlszeilenoption (oder ein Aufruf des Warnings-Moduls), dass an dieser Stelle eine Warnung oder ein Fehler ausgegeben wird, dies ist jedoch standardmäßig deaktiviert. - Die verbleibenden semantischen Unterschiede werden behandelt. In allen Fällen wird die Semantik von langen ints gelten. Da dies zu Rückwärtsinkompatibilitäten führt, die einigen alten Code brechen werden, erfordert diese Phase möglicherweise eine zukünftige Aussage und/oder Warnungen und eine verlängerte Übergangsphase. Das nachgestellte L wird weiterhin für lange ints bei der Eingabe und von
repr()verwendet.- Warnungen werden für Operationen aktiviert, die ihre numerischen Ergebnisse in Phase 2B ändern werden, insbesondere
hex()undoct(),%u,%x,%Xund%o, hex- und oct-Literale im (einschließlich) Bereich[sys.maxint+1, sys.maxint*2+1]und Linksverschiebungen, die Bits verlieren. - Die neue Semantik für diese Operationen wird implementiert. Operationen, die andere Ergebnisse als zuvor liefern, geben *keine* Warnung aus.
- Warnungen werden für Operationen aktiviert, die ihre numerischen Ergebnisse in Phase 2B ändern werden, insbesondere
- Das nachgestellte L wird aus
repr()entfernt und bei der Eingabe illegal gemacht. (Wenn möglich, verschwindet derlong-Typ vollständig.) Das nachgestellte L wird auch aushex()undoct()entfernt.
Phase 1 wird in Python 2.2 implementiert.
Phase 2 wird schrittweise implementiert, 2A in Python 2.3 und 2B in Python 2.4.
Phase 3 wird in Python 3.0 implementiert (mindestens zwei Jahre nach der Veröffentlichung von Python 2.4).
OverflowWarning
Hier sind die Regeln, die die Warnungen leiten, die in Situationen generiert werden, die derzeit OverflowError auslösen. Dies gilt für die Übergangsphase 1. Historischer Hinweis: Obwohl Phase 1 in Python 2.2 und Phase 2A in Python 2.3 abgeschlossen wurden, bemerkte niemand, dass OverflowWarning in Python 2.3 immer noch generiert wurde. Es wurde schließlich in Python 2.4 deaktiviert. Die Python-eingebaute OverflowWarning und die entsprechende C-API PyExc_OverflowWarning werden in Python 2.4 nicht mehr generiert oder verwendet, bleiben aber für den (unwahrscheinlichen) Fall von Benutzercode bis Python 2.5 bestehen.
- Eine neue Warnungskategorie wird eingeführt,
OverflowWarning. Dies ist ein eingebauter Name. - Wenn ein Int-Ergebnis überläuft, wird eine
OverflowWarning-Warnung ausgegeben, mit einem Nachrichtenargument, das die Operation angibt, z.B. „integer addition“. Dies kann möglicherweise eine Warnmeldung aufsys.stderranzeigen, oder einen Fehler auslösen, alles gesteuert durch die-WBefehlszeilenoption und das warnings-Modul. - Die
OverflowWarning-Warnung wird standardmäßig ignoriert. - Die
OverflowWarning-Warnung kann wie alle Warnungen gesteuert werden, über die-WBefehlszeilenoption oder über denwarnings.filterwarnings()Aufruf. Zum Beispielpython -Wdefault::OverflowWarning
die
OverflowWarningzum ersten Mal, wenn sie an einer bestimmten Quellcodezeile auftritt, anzeigen lassen, undpython -Werror::OverflowWarning
die
OverflowWarningin eine Ausnahme umwandeln lassen, wann immer sie auftritt. Der folgende Code aktiviert die Warnung aus dem Programm herausimport warnings warnings.filterwarnings("default", "", OverflowWarning)
Siehe die Python
man-Seite für die-W-Option und die Dokumentation deswarnings-Moduls fürfilterwarnings(). - Wenn die
OverflowWarning-Warnung in eine Ausnahme umgewandelt wird, wirdOverflowErroreingesetzt. Dies ist aus Gründen der Abwärtskompatibilität erforderlich. - Wenn die Warnung nicht in eine Ausnahme umgewandelt wird, wird das Ergebnis der Operation (z.B.
x+y) neu berechnet, nachdem die Argumente in lange ints konvertiert wurden.
Beispiel
Wenn Sie einen langen int an eine C-Funktion oder eine eingebaute Operation übergeben, die einen Integer erwartet, wird er wie ein kurzer int behandelt, solange der Wert passt (aufgrund der Implementierung von PyArg_ParseTuple()). Wenn der lange Wert nicht passt, wird immer noch ein OverflowError ausgelöst. Zum Beispiel
def fact(n):
if n <= 1:
return 1
return n*fact(n-1)
A = "ABCDEFGHIJKLMNOPQ"
n = input("Gimme an int: ")
print A[fact(n)%17]
Für n >= 13 löst dies derzeit OverflowError aus (es sei denn, der Benutzer gibt ein nachgestelltes L als Teil seiner Eingabe ein), obwohl der berechnete Index immer im Bereich range(17) liegen würde. Mit dem neuen Ansatz wird dieser Code das Richtige tun: der Index wird als langer int berechnet, aber sein Wert liegt im Bereich.
Gelöste Probleme
Diese zuvor offenen Fragen sind gelöst worden.
hex()undoct(), angewendet auf lange ints, erzeugen weiterhin ein nachgestelltes L bis Python 3000. Der ursprüngliche Text war hier nicht klar, aber da es in Python 2.4 nicht geschah, wurde beschlossen, es so zu belassen. BDFL-Erklärung hierhttps://mail.python.org/pipermail/python-dev/2006-June/065918.html
- Was tun mit
sys.maxint? Beibehalten, da es immer noch relevant ist, wenn die Unterscheidung zwischen kurzen und langen ints noch relevant ist (z.B. bei der Inspektion des Typs eines Werts). - Sollen wir
%ukomplett entfernen? Entfernen. - Sollen wir vor
<<warnen, das ganze Zahlen nicht abschneidet? Ja. - Soll die Überlaufwarnung bei einer portablen Maximalgröße liegen? Nein.
Implementierung
Die Implementierungsarbeiten für die Python 2.x-Reihe sind abgeschlossen; Phase 1 wurde mit Python 2.2 veröffentlicht, Phase 2A mit Python 2.3 und Phase 2B wird mit Python 2.4 veröffentlicht (und ist bereits in CVS).
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0237.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT