PEP 225 – Elementweise/Objektweise Operatoren
- Autor:
- Huaiyu Zhu <hzhu at users.sourceforge.net>, Gregory Lielens <gregory.lielens at fft.be>
- Status:
- Abgelehnt
- Typ:
- Standards Track
- Erstellt:
- 19-Sep-2000
- Python-Version:
- 2.1
- Post-History:
Inhaltsverzeichnis
- Einleitung
- Hintergrund
- Vorgeschlagene Erweiterung
- Prototyp-Implementierung
- Alternativen zur Einführung neuer Operatoren
- Alternative Formen von Infix-Operatoren
- Semantik der neuen Operatoren
- Beispiele
- Verschiedene Themen
- Auswirkungen auf allgemeine Elementarisierung
- Auswirkungen auf benannte Operatoren
- Danksagungen und Archive
- Zusätzliche Referenzen
Einleitung
Dieses PEP beschreibt einen Vorschlag zur Einführung neuer Operatoren in Python, die für die Unterscheidung von elementweisen und objektweisen Operationen nützlich sind, und fasst die Diskussionen in der Nachrichtengruppe comp.lang.python zu diesem Thema zusammen. Siehe Abschnitt Danksagungen und Archive am Ende. Hier besprochene Themen umfassen
- Hintergrund.
- Beschreibung der vorgeschlagenen Operatoren und Implementierungsfragen.
- Analyse von Alternativen zu neuen Operatoren.
- Analyse alternativer Formen.
- Kompatibilitätsprobleme
- Beschreibung breiterer Erweiterungen und anderer verwandter Ideen.
Ein beträchtlicher Teil dieses PEPs beschreibt Ideen, die nicht in die vorgeschlagene Erweiterung einfließen. Sie werden präsentiert, da die Erweiterung im Wesentlichen syntaktischer Zucker ist, so dass ihre Annahme gegen verschiedene mögliche Alternativen abgewogen werden muss. Während viele Alternativen in einigen Aspekten besser sein mögen, erscheint der aktuelle Vorschlag insgesamt vorteilhaft.
Die Fragen bezüglich elementweiser-objektweiser Operationen erstrecken sich auf breitere Bereiche als die numerische Berechnung. Dieses Dokument beschreibt auch, wie der aktuelle Vorschlag mit allgemeineren zukünftigen Erweiterungen integriert werden kann.
Hintergrund
Python bietet sechs binäre Infix-Mathematikoperatoren: + - * / % **, die im Folgenden generisch durch op dargestellt werden. Sie können mit neuer Semantik für benutzerdefinierte Klassen überladen werden. Bei Objekten, die aus homogenen Elementen bestehen, wie Arrays, Vektoren und Matrizen in der numerischen Berechnung, gibt es jedoch zwei im Wesentlichen unterschiedliche Arten von Semantik. Die objektweisen Operationen behandeln diese Objekte als Punkte in mehrdimensionalen Räumen. Die elementweisen Operationen behandeln sie als Sammlungen einzelner Elemente. Diese beiden Arten von Operationen sind oft in denselben Formeln vermischt, was eine syntaktische Unterscheidung erfordert.
Viele Sprachen für numerische Berechnungen bieten zwei Sätze von Mathematikoperatoren. Zum Beispiel wird in MatLab der gewöhnliche op für objektweise Operationen verwendet, während .op für elementweise Operationen verwendet wird. In R steht op für elementweise Operationen, während %op% für objektweise Operationen steht.
In Python gibt es andere Darstellungsformen, von denen einige bereits von verfügbaren numerischen Paketen verwendet werden, wie z. B.
- Funktion: mul(a,b)
- Methode: a.mul(b)
- Casting: a.E*b
In mehreren Aspekten sind diese nicht so gut wie Infix-Operatoren. Mehr Details werden später gezeigt, aber die Kernpunkte sind
- Lesbarkeit: Selbst für mäßig komplizierte Formeln sind Infix-Operatoren viel sauberer als Alternativen.
- Vertrautheit: Benutzer sind mit gewöhnlichen Mathematikoperatoren vertraut.
- Implementierung: Neue Infix-Operatoren werden die Python-Syntax nicht unnötig überladen. Sie werden die Implementierung numerischer Pakete erheblich erleichtern.
Obwohl es möglich ist, aktuelle Mathematikoperatoren einer Art von Semantik zuzuweisen, gibt es einfach nicht genügend Infix-Operatoren, um sie für die andere Art zu überladen. Es ist auch unmöglich, die visuelle Symmetrie zwischen diesen beiden Arten beizubehalten, wenn eine von ihnen keine Symbole für gewöhnliche Mathematikoperatoren enthält.
Vorgeschlagene Erweiterung
- Sechs neue binäre Infix-Operatoren
~+~-~*~/~%~**werden zu Python hinzugefügt. Sie spiegeln die bestehenden Operatoren+-*/%**wider. - Sechs erweiterte Zuweisungsoperatoren
~+=~-=~*=~/=~%=~**=werden zu Python hinzugefügt. Sie spiegeln die Operatoren+=-=*=/=%=**=wider, die in Python 2.0 verfügbar sind. - Der Operator
~opbehält die syntaktischen Eigenschaften des Operatorsop, einschließlich der Präzedenz. - Der Operator
~opbehält die semantischen Eigenschaften des Operatorsopfür integrierte Zahlentypen. - Der Operator
~oplöst bei nicht-numerischen integrierten Typen einen Syntaxfehler aus. Dies ist vorläufig, bis das richtige Verhalten vereinbart werden kann. - Diese Operatoren sind in Klassen mit Namen überladbar, die ein *t* (für Tilde) vor den Namen gewöhnlicher Mathematikoperatoren stellen. Zum Beispiel funktionieren
__tadd__und__rtadd__für~+genauso wie__add__und__radd__für+funktionieren. - Wie bei bestehenden Operatoren werden die Methoden
__r*__()aufgerufen, wenn der linke Operand die entsprechende Methode nicht bereitstellt.
Es ist beabsichtigt, dass ein Satz von op oder ~op für elementweise Operationen und der andere für objektweise Operationen verwendet wird. Es ist jedoch nicht spezifiziert, welche Version der Operatoren für elementweise oder objektweise Operationen steht, wodurch die Entscheidung den Anwendungen überlassen wird.
Die vorgeschlagene Implementierung besteht darin, mehrere Dateien zu patchen, die sich auf den Tokenizer, Parser, die Grammatik und den Compiler beziehen, um die Funktionalität der entsprechenden bestehenden Operatoren nach Bedarf zu duplizieren. Alle neuen Semantiken sollen in den Klassen implementiert werden, die sie überladen.
Das Symbol ~ wird in Python bereits als unärer *Bitwise Not*-Operator verwendet. Derzeit ist es für binäre Operatoren nicht erlaubt. Die neuen Operatoren sind vollständig abwärtskompatibel.
Prototyp-Implementierung
Greg Lielens implementierte den Infix-Operator ~op als Patch gegen den Quellcode von Python 2.0b1 [1].
Um ~ als Teil von binären Operatoren zu erlauben, würde der Tokenizer ~+ als ein Token behandeln. Das bedeutet, dass der derzeit gültige Ausdruck ~+1 als ~+ 1 und nicht als ~ + 1 tokenisiert würde. Der Parser würde ~+ dann als eine Zusammensetzung aus ~ + behandeln. Die Auswirkung ist für Anwendungen unsichtbar.
Hinweise zum aktuellen Patch
- Er beinhaltet noch keine
~op=-Operatoren. - Der
~opverhält sich bei Listen genauso wieop, anstatt Ausnahmen auszulösen.
Diese sollten behoben werden, wenn die endgültige Version dieses Vorschlags fertig ist.
- Er reserviert
xorals Infix-Operator mit der Semantik, die äquivalent ist zudef __xor__(a, b): if not b: return a elif not a: return b else: 0
Dies bewahrt den tatsächlichen Wert so weit wie möglich, andernfalls wird der linke Teilwert, wenn möglich, bewahrt.
Dies geschieht, damit bitweise Operatoren zukünftig als elementweise logische Operatoren betrachtet werden können (siehe unten).
Alternativen zur Einführung neuer Operatoren
Die Diskussionen auf comp.lang.python und der Mailingliste python-dev haben viele Alternativen erforscht. Einige der führenden Alternativen sind hier aufgelistet, wobei der Multiplikationsoperator als Beispiel dient.
- Verwendung der Funktion
mul(a,b).Vorteil
- Keine Notwendigkeit für neue Operatoren.
Nachteil
- Präfix-Formen sind für zusammengesetzte Formeln umständlich.
- Für die beabsichtigten Benutzer ungewohnt.
- Zu wortreich für die beabsichtigten Benutzer.
- Kann keine natürlichen Präzedenzregeln verwenden.
- Verwendung des Methodenaufrufs
a.mul(b).Vorteil
- Keine Notwendigkeit für neue Operatoren.
Nachteil
- Asymmetrisch für beide Operanden.
- Für die beabsichtigten Benutzer ungewohnt.
- Zu wortreich für die beabsichtigten Benutzer.
- Kann keine natürlichen Präzedenzregeln verwenden.
- Verwendung von *Schattenklassen*. Für eine Matrixklasse eine Schatten-Array-Klasse definieren, die über eine Methode
.Ezugänglich ist, so dass für Matrizen *a* und *b*a.E*bein Matrixobjekt wäre, daselementwise_mul(a,b)ist.Ebenso eine Schatten-Matrixklasse für Arrays definieren, die über eine Methode
.Mzugänglich ist, so dass für Arrays *a* und *b*a.M*bein Array wäre, dasmatrixwise_mul(a,b)ist.Vorteil
- Keine Notwendigkeit für neue Operatoren.
- Vorteile von Infix-Operatoren mit korrekten Präzedenzregeln.
- Saubere Formeln in Anwendungen.
Nachteil
- Schwer zu warten im aktuellen Python, da gewöhnliche Zahlen keine benutzerdefinierten Klassenmethoden haben können; d. h.
a.E*bschlägt fehl, wenn a eine reine Zahl ist. - Schwer zu implementieren, da dies bestehende Methodenaufrufe stört, wie z. B.
.Tfür Transponierung usw. - Laufzeit-Overhead für Objekterstellung und Methodenaufruf.
- Die Schattenklasse kann keine echte Klasse ersetzen, da sie nicht ihren eigenen Typ zurückgibt. Daher muss es eine
M-Klasse mit einer Schatten-E-Klasse und eineE-Klasse mit einer Schatten-M-Klasse geben. - Unnatürlich für Mathematiker.
- Implementierung von Matrix- und Element-Klassen mit einfachem Casting zur anderen Klasse. Matrixweise Operationen für Arrays wären also wie
a.M*b.Mund elementweise Operationen für Matrizen wiea.E*b.E. Zur Fehlererkennung würdea.E*b.MAusnahmen auslösen.Vorteil
- Keine Notwendigkeit für neue Operatoren.
- Ähnlich wie Infix-Notation mit korrekten Präzedenzregeln.
Nachteil
- Ähnliche Schwierigkeit aufgrund des Fehlens von Benutzer-Methoden für reine Zahlen.
- Laufzeit-Overhead für Objekterstellung und Methodenaufruf.
- Mehr überladene Formeln.
- Das Umschalten des Objektflügels zur Erleichterung der Operatoren wird persistent. Dies führt zu Langzeitkontextabhängigkeiten im Anwendungscode, die extrem schwer zu warten wären.
- Verwendung eines Mini-Parsers zum Parsen von Formeln, die in beliebigen Erweiterungen in Anführungszeichen geschrieben sind.
Vorteil
- Reines Python, ohne neue Operatoren
Nachteil
- Die eigentliche Syntax befindet sich innerhalb der Anführungszeichen, was das Problem selbst nicht löst.
- Einführung von Zonen mit spezieller Syntax.
- Anspruchsvoll an den Mini-Parser.
- Einführung eines einzigen Operators, wie z. B.
@, für die Matrixmultiplikation.Vorteil
- Führt weniger Operatoren ein
Nachteil
- Die Unterscheidungen für Operatoren wie
+-**sind ebenso wichtig. Ihre Bedeutung in matrix- oder array-orientierten Paketen würde umgekehrt (siehe unten). - Der neue Operator belegt ein Sonderzeichen.
- Dies funktioniert nicht gut mit allgemeineren Objekt-Element-Problemen.
Unter diesen Alternativen werden die erste und die zweite in aktuellen Anwendungen bis zu einem gewissen Grad verwendet, aber als unzureichend befunden. Die dritte ist die beliebteste für Anwendungen, aber sie wird enorme Implementierungskomplexität mit sich bringen. Die vierte würde Anwendungscodes sehr kontextsensitiv und schwer zu warten machen. Diese beiden Alternativen teilen auch erhebliche Implementierungsschwierigkeiten aufgrund der aktuellen Typ-/Klassenaufteilung. Die fünfte scheint mehr Probleme zu schaffen, als sie lösen würde. Die sechste deckt nicht den gleichen Anwendungsbereich ab.
Alternative Formen von Infix-Operatoren
Zwei Hauptformen und mehrere Nebenvarianten von neuen Infix-Operatoren wurden diskutiert
- Klammerform
(op) [op] {op} <op> :op: ~op~ %op%
- Meta-Zeichen-Form
.op @op ~op
Alternativ wird das Meta-Zeichen nach dem Operator platziert.
- Weniger konsistente Variationen dieser Themen. Diese werden ungünstig betrachtet. Vollständigkeitshalber sind einige hier aufgelistet
- Verwendung von
@/und/@für Links- und Rechtsdivision - Verwendung von
[*]und(*)für Außen- und Innenprodukt - Verwendung eines einzelnen Operators
@für die Multiplikation.
- Verwendung von
- Verwendung von
__call__zur Simulation der Multiplikationa(b) or (a)(b)
Kriterien für die Auswahl unter den Darstellungen sind
- Keine syntaktischen Mehrdeutigkeiten mit bestehenden Operatoren.
- Höhere Lesbarkeit in tatsächlichen Formeln. Dies macht die Klammerformen ungünstig. Siehe Beispiele unten.
- Visuell den bestehenden Mathematikoperatoren ähnlich.
- Syntaktisch einfach, ohne mögliche zukünftige Erweiterungen zu blockieren.
Mit diesen Kriterien ist der Gesamtsieger in Klammerform {op}. Ein klarer Sieger in der Meta-Zeichen-Form ist ~op. Beim Vergleich dieser beiden scheint ~op der Favorit unter allen zu sein.
Einige Analysen sind wie folgt
- Die Form
.opist mehrdeutig:1.+awäre anders als1 .+a. - Die Klammertyp-Operatoren sind am günstigsten, wenn sie allein stehen, aber nicht in Formeln, da sie die visuelle Analyse von Klammern für Präzedenz und Funktionsargumente stören. Dies gilt für
(op)und[op], und etwas weniger für{op}und<op>. - Die Form
<op>hat das Potenzial, mit<>und=verwechselt zu werden. @opwird nicht bevorzugt, da@visuell schwerfällig ist (dicht, eher wie ein Buchstabe):a@+bwird leichter alsa@ + bdenn alsa @+ bgelesen.- Für die Wahl von Meta-Zeichen: Die meisten vorhandenen ASCII-Symbole wurden bereits verwendet. Die einzigen drei ungenutzten sind
@$?.
Semantik der neuen Operatoren
Es gibt überzeugende Argumente für die Verwendung beider Sätze von Operatoren als objektweise oder elementweise. Einige davon sind hier aufgelistet
opfür Elemente,~opfür Objekte- Konsistent mit der aktuellen Multiarray-Schnittstelle des Numeric-Pakets.
- Konsistent mit einigen anderen Sprachen.
- Wahrnehmung, dass elementweise Operationen natürlicher sind.
- Wahrnehmung, dass elementweise Operationen häufiger verwendet werden
opfür Objekte,~opfür Elemente- Konsistent mit der aktuellen Lineare-Algebra-Schnittstelle des MatPy-Pakets.
- Konsistent mit einigen anderen Sprachen.
- Wahrnehmung, dass objektweise Operationen natürlicher sind.
- Wahrnehmung, dass objektweise Operationen häufiger verwendet werden.
- Konsistent mit dem aktuellen Verhalten von Operatoren für Listen.
- Erlaubt
~als allgemeines elementweises Meta-Zeichen für zukünftige Erweiterungen.
Es herrscht allgemein Einigkeit darüber, dass
- Es keinen absoluten Grund gibt, das eine dem anderen vorzuziehen.
- Es einfach ist, von einer Darstellung zur anderen in einem beträchtlichen Teil des Codes zu konvertieren, so dass die andere Art von Operatoren immer die Minderheit ist.
- Es andere semantische Unterschiede gibt, die für die Existenz von Array-orientierten und Matrix-orientierten Paketen sprechen, auch wenn ihre Operatoren vereinheitlicht sind.
- Welche Entscheidung auch immer getroffen wird, Codes, die bestehende Schnittstellen verwenden, sollten nicht sehr lange defekt sein.
Daher geht nicht viel verloren, und es bleibt viel Flexibilität erhalten, wenn die semantischen Ausprägungen dieser beiden Sätze von Operatoren nicht von der Kernsprache diktiert werden. Die Anwendungspakete sind dafür verantwortlich, die am besten geeignete Wahl zu treffen. Dies ist bereits bei NumPy und MatPy der Fall, die entgegengesetzte Semantik verwenden. Das Hinzufügen neuer Operatoren wird dies nicht brechen. Siehe auch die Beobachtung nach Unterabschnitt 2 in den Beispielen unten.
Die Frage der numerischen Präzision wurde aufgeworfen, aber wenn die Semantik den Anwendungen überlassen wird, sollte die tatsächliche Präzision ebenfalls dorthin gehen.
Beispiele
Folgend sind Beispiele für tatsächliche Formeln, die mit verschiedenen Operatoren oder anderen oben beschriebenen Darstellungen erscheinen werden.
- Die Formel für die Matrixinversion
- Verwendung von
opfür Objekte und~opfür Elementeb = a.I - a.I * u / (c.I + v/a*u) * v / a b = a.I - a.I * u * (c.I + v*a.I*u).I * v * a.I
- Verwendung von
opfür Elemente und~opfür Objekteb = a.I @- a.I @* u @/ (c.I @+ v@/a@*u) @* v @/ a b = a.I ~- a.I ~* u ~/ (c.I ~+ v~/a~*u) ~* v ~/ a b = a.I (-) a.I (*) u (/) (c.I (+) v(/)a(*)u) (*) v (/) a b = a.I [-] a.I [*] u [/] (c.I [+] v[/]a[*]u) [*] v [/] a b = a.I <-> a.I <*> u </> (c.I <+> v</>a<*>u) <*> v </> a b = a.I {-} a.I {*} u {/} (c.I {+} v{/}a{*}u) {*} v {/} a
Beobachtung: Für die lineare Algebra ist die Verwendung von
opfür Objekte vorzuziehen.Beobachtung: Die
~op-Typ-Operatoren sehen besser aus als(op)-Typen in komplizierten Formeln.- Verwendung benannter Operatoren
b = a.I @sub a.I @mul u @div (c.I @add v @div a @mul u) @mul v @div a b = a.I ~sub a.I ~mul u ~div (c.I ~add v ~div a ~mul u) ~mul v ~div a
Beobachtung: Benannte Operatoren sind für mathematische Formeln nicht geeignet.
- Verwendung von
- Plotten eines 3D-Graphen
- Verwendung von
opfür Objekte und~opfür Elementez = sin(x~**2 ~+ y~**2); plot(x,y,z)
- Verwendung von op für Elemente und ~op für Objekte
z = sin(x**2 + y**2); plot(x,y,z)
Beobachtung: Elementweise Operationen mit Broadcasting ermöglichen eine viel effizientere Implementierung als MatLab.
Beobachtung: Es ist nützlich, zwei verwandte Klassen mit der Semantik von
opund~opvertauscht zu haben. Mit diesen müssten die~op-Operatoren nur in Codeabschnitten erscheinen, in denen die andere Art dominiert, während die konsistente Semantik des Codes beibehalten wird. - Verwendung von
- Verwendung von
+und-mit automatischem Broadcastinga = b - c; d = a.T*a
Beobachtung: Dies würde stillschweigend zu schwer zu verfolgenden Fehlern führen, wenn einer von *b* oder *c* ein Zeilenvektor und der andere ein Spaltenvektor ist.
Verschiedene Themen
- Bedarf an den Operatoren
~+~-. Die objektweisen+-sind wichtig, da sie wichtige Überprüfungen gemäß der Linearen Algebra bieten. Die elementweisen+-sind wichtig, da sie Broadcasting ermöglichen, das in Anwendungen sehr effizient ist. - Linke Division (lösen). Für eine Matrix ist
a*xnicht unbedingt gleichx*a. Die Lösung vona*x==b, bezeichnet alsx=solve(a,b), ist daher anders als die Lösung vonx*a==b, bezeichnet alsx=div(b,a). Es gibt Diskussionen über die Suche nach einem neuen Symbol für "solve". [Hintergrund: MatLab verwendetb/afürdiv(b,a)unda\bfürsolve(a,b).]Es wird erkannt, dass Python eine bessere Lösung bietet, ohne ein neues Symbol zu benötigen: Die Methode
inverse.Ikann so verzögert werden, dassa.I*bundb*a.Iäquivalent zu Matlabsa\bundb/asind. Die Implementierung ist recht einfach und der resultierende Anwendungscode sauber. - Potenzoperator. Pythons Verwendung von
a**balspow(a,b)hat zwei wahrgenommene Nachteile- Die meisten Mathematiker sind mit
a^bfür diesen Zweck vertrauter. - Es führt zu einem langen erweiterten Zuweisungsoperator
~**=.
Dieses Thema ist jedoch vom Hauptthema hier getrennt.
- Die meisten Mathematiker sind mit
- Zusätzliche Multiplikationsoperatoren. Verschiedene Formen von Multiplikationen werden in der (Multi-)Linearen Algebra verwendet. Die meisten können als Variationen der Multiplikation im Sinne der Linearen Algebra betrachtet werden (z. B. Kronecker-Produkt). Zwei Formen scheinen jedoch grundlegender zu sein: Außenprodukt und Innenprodukt. Ihre Spezifikation beinhaltet jedoch Indizes, die entweder sein können
- dem Operator zugeordnet, oder
- den Objekten zugeordnet.
Letzteres (die Einstein-Notation) wird auf Papier extensiv verwendet und ist auch einfacher zu implementieren. Durch die Implementierung einer Tensor-mit-Indizes-Klasse würde eine allgemeine Form der Multiplikation sowohl Außen- als auch Innenprodukte abdecken und sich auch auf die Lineare Algebra-Multiplikation spezialisieren. Die Indexregel kann als Klassenmethode definiert werden, wie
a = b.i(1,2,-1,-2) * c.i(4,-2,3,-1) # a_ijkl = b_ijmn c_lnkm
Daher reicht eine objektweise Multiplikation aus.
- Bitweise Operatoren.
- Die vorgeschlagenen neuen Mathematikoperatoren verwenden das Symbol ~, das der *Bitwise Not*-Operator ist. Dies stellt kein Kompatibilitätsproblem dar, erschwert jedoch die Implementierung.
- Das Symbol
^könnte besser fürpowals für das bitweisexorverwendet werden. Dies hängt jedoch von der Zukunft der bitweisen Operatoren ab. Es hat keine unmittelbaren Auswirkungen auf den vorgeschlagenen Mathematikoperator. - Das Symbol
|wurde vorgeschlagen, um für Matrix-Solve verwendet zu werden. Die neue Lösung mit verzögertem.Iist jedoch in mehrfacher Hinsicht besser. - Der aktuelle Vorschlag passt in eine größere und allgemeinere Erweiterung, die die Notwendigkeit von speziellen bitweisen Operatoren beseitigen wird. (Siehe Elementarisierung unten.)
- Alternative zu speziellen Operatornamen, die in der Definition verwendet werden,
def "+"(a, b) in place of def __add__(a, b)
Dies scheint größere syntaktische Änderungen zu erfordern und wäre nur nützlich, wenn beliebige zusätzliche Operatoren erlaubt wären.
Auswirkungen auf allgemeine Elementarisierung
Die Unterscheidung zwischen objektweisen und elementweisen Operationen ist auch in anderen Kontexten sinnvoll, in denen ein Objekt konzeptionell als Sammlung von Elementen betrachtet werden kann. Es ist wichtig, dass der aktuelle Vorschlag mögliche zukünftige Erweiterungen nicht ausschließt.
Eine allgemeine zukünftige Erweiterung besteht darin, ~ als Meta-Operator zu verwenden, um einen gegebenen Operator zu *elementisieren*. Mehrere Beispiele sind hier aufgeführt
- Bitweise Operatoren. Derzeit weist Python sechs Operatoren Bitoperationen zu: and (
&), or (|), xor (^), complement (~), left shift (<<) und right shift (>>), mit ihren eigenen Präzedenzebenen.Unter ihnen können die Operatoren
&|^~als elementweise Versionen von Gitteroperatoren betrachtet werden, die auf ganze Zahlen angewendet werden, die als Bitstrings betrachtet werden.5 and 6 # 6 5 or 6 # 5 5 ~and 6 # 4 5 ~or 6 # 7
Diese können als allgemeine elementweise Gitteroperatoren betrachtet werden, die nicht auf Bits in ganzen Zahlen beschränkt sind.
Um benannte Operatoren für
xor~xorzu haben, ist es notwendig,xorzu einem reservierten Wort zu machen. - Listen-Arithmetik.
[1, 2] + [3, 4] # [1, 2, 3, 4] [1, 2] ~+ [3, 4] # [4, 6] ['a', 'b'] * 2 # ['a', 'b', 'a', 'b'] 'ab' * 2 # 'abab' ['a', 'b'] ~* 2 # ['aa', 'bb'] [1, 2] ~* 2 # [2, 4]
Es ist auch konsistent mit dem kartesischen Produkt
[1,2]*[3,4] # [(1,3),(1,4),(2,3),(2,4)]
- List Comprehension.
a = [1, 2]; b = [3, 4] ~f(a,b) # [f(x,y) for x, y in zip(a,b)] ~f(a*b) # [f(x,y) for x in a for y in b] a ~+ b # [x + y for x, y in zip(a,b)]
- Tupel-Generierung (die `zip`-Funktion in Python 2.0)
[1, 2, 3], [4, 5, 6] # ([1,2, 3], [4, 5, 6]) [1, 2, 3]~,[4, 5, 6] # [(1,4), (2, 5), (3,6)]
- Verwendung von
~als generisches elementweises Meta-Zeichen zur Ersetzung von `map`~f(a, b) # map(f, a, b) ~~f(a, b) # map(lambda *x:map(f, *x), a, b)
Allgemeiner,
def ~f(*x): return map(f, *x) def ~~f(*x): return map(~f, *x) ...
- Elementweiser Formatoperator (mit Broadcasting)
a = [1,2,3,4,5] print ["%5d "] ~% a a = [[1,2],[3,4]] print ["%5d "] ~~% a
- Reichhaltige Vergleiche
[1, 2, 3] ~< [3, 2, 1] # [1, 0, 0] [1, 2, 3] ~== [3, 2, 1] # [0, 1, 0]
- Reichhaltige Indizierung
[a, b, c, d] ~[2, 3, 1] # [c, d, b]
- Tupel-Abflachung
a = (1,2); b = (3,4) f(~a, ~b) # f(1,2,3,4)
- Kopieroperator
a ~= b # a = b.copy()
Es kann spezifische Ebenen der Tiefenkopie gebena ~~= b # a = b.copy(2)
Anmerkungen
- Es gibt wahrscheinlich viele andere ähnliche Situationen. Dieser allgemeine Ansatz scheint für die meisten von ihnen gut geeignet zu sein, anstelle mehrerer getrennter Erweiterungen für jede von ihnen (parallele und kreuzweise Iteration, List Comprehension, reiche Vergleiche usw.).
- Die Semantik von *elementweise* hängt von den Anwendungen ab. Zum Beispiel ist ein Element einer Matrix aus der Sicht einer Liste-in-Liste zwei Ebenen tiefer. Dies erfordert grundlegendere Änderungen als der aktuelle Vorschlag. In jedem Fall wird der aktuelle Vorschlag zukünftige Möglichkeiten dieser Art nicht negativ beeinflussen.
Beachten Sie, dass dieser Abschnitt eine Art von zukünftigen Erweiterungen beschreibt, die mit dem aktuellen Vorschlag konsistent sind, aber zusätzliche Kompatibilitäts- oder andere Probleme aufweisen können. Sie sind nicht an den aktuellen Vorschlag gebunden.
Auswirkungen auf benannte Operatoren
Die Diskussionen haben im Allgemeinen verdeutlicht, dass Infixoperatoren in Python eine knappe Ressource sind, nicht nur in der numerischen Berechnung, sondern auch in anderen Bereichen. Mehrere Vorschläge und Ideen wurden vorgebracht, die die Einführung von Infixoperatoren ähnlich wie benannte Funktionen ermöglichen würden. Wir zeigen hier, dass die aktuelle Erweiterung zukünftige Erweiterungen in dieser Hinsicht nicht negativ beeinflusst.
- Benannte Infixoperatoren.
Wählen Sie ein Metazeichen, z. B.
@, so dass für jeden Bezeichneropnamedie Kombination@opnameein binärer Infixoperator wäre, unda @opname b == opname(a,b)
Andere erwähnte Darstellungen umfassen
.name ~name~ :name: (.name) %name%
und ähnliche Variationen. Reine klammerbasierte Operatoren können nicht auf diese Weise verwendet werden.
Dies erfordert eine Änderung im Parser, um
@opnamezu erkennen und in dieselbe Struktur wie ein Funktionsaufruf zu parsen. Die Präzedenz aller dieser Operatoren müsste auf einer Ebene festgelegt werden, daher wäre die Implementierung anders als bei zusätzlichen mathematischen Operatoren, die die Präzedenz bestehender mathematischer Operatoren beibehalten.Die aktuell vorgeschlagene Erweiterung schränkt mögliche zukünftige Erweiterungen dieser Form in keiner Weise ein.
- Allgemeinere symbolische Operatoren.
Eine zusätzliche Form zukünftiger Erweiterung ist die Verwendung von Metazeichen und Operatorsymbolen (Symbole, die in syntaktischen Strukturen außer Operatoren nicht verwendet werden können). Angenommen,
@ist das Metazeichen. Danna + b, a @+ b, a @@+ b, a @+- b
wären alle Operatoren mit einer Präzedenzhierarchie, definiert durch
def "+"(a, b) def "@+"(a, b) def "@@+"(a, b) def "@+-"(a, b)
Ein Vorteil gegenüber benannten Operatoren ist die größere Flexibilität bei der Präzedenz, die entweder auf dem Metazeichen oder den normalen Operatorsymbolen basiert. Dies ermöglicht auch die Operatorzusammensetzung. Der Nachteil ist, dass sie eher wie "Zeilenrauschen" sind. In jedem Fall beeinträchtigt der aktuelle Vorschlag dessen zukünftige Möglichkeit nicht.
Diese Arten von zukünftigen Erweiterungen sind möglicherweise nicht notwendig, wenn Unicode allgemein verfügbar wird.
Beachten Sie, dass dieser Abschnitt die Kompatibilität der vorgeschlagenen Erweiterung mit möglichen zukünftigen Erweiterungen diskutiert. Die Wünschbarkeit oder Kompatibilität dieser anderen Erweiterungen selbst wird hier ausdrücklich nicht berücksichtigt.
Danksagungen und Archive
Die Diskussionen fanden hauptsächlich im Juli bis August 2000 in der Newsgruppe comp.lang.python und der Mailingliste python-dev statt. Es gibt insgesamt mehrere hundert Beiträge, die meisten können von diesen beiden Seiten abgerufen werden (und durch Suche nach dem Wort „operator“).
Die Namen der Mitwirkenden sind zu zahlreich, um sie hier zu erwähnen. Es genügt zu sagen, dass ein großer Teil der hier diskutierten Ideen nicht unsere eigenen ist.
Mehrere Schlüsselbeiträge (aus unserer Sicht), die bei der Navigation durch die Diskussionen helfen können, sind:
https://pythonlang.de/pipermail/python-list/2000-July/108893.html https://pythonlang.de/pipermail/python-list/2000-July/108777.html https://pythonlang.de/pipermail/python-list/2000-July/108848.html https://pythonlang.de/pipermail/python-list/2000-July/109237.html https://pythonlang.de/pipermail/python-list/2000-July/109250.html https://pythonlang.de/pipermail/python-list/2000-July/109310.html https://pythonlang.de/pipermail/python-list/2000-July/109448.html https://pythonlang.de/pipermail/python-list/2000-July/109491.html https://pythonlang.de/pipermail/python-list/2000-July/109537.html https://pythonlang.de/pipermail/python-list/2000-July/109607.html https://pythonlang.de/pipermail/python-list/2000-July/109709.html https://pythonlang.de/pipermail/python-list/2000-July/109804.html https://pythonlang.de/pipermail/python-list/2000-July/109857.html https://pythonlang.de/pipermail/python-list/2000-July/110061.html https://pythonlang.de/pipermail/python-list/2000-July/110208.html https://pythonlang.de/pipermail/python-list/2000-August/111427.html https://pythonlang.de/pipermail/python-list/2000-August/111558.html https://pythonlang.de/pipermail/python-list/2000-August/112551.html https://pythonlang.de/pipermail/python-list/2000-August/112606.html https://pythonlang.de/pipermail/python-list/2000-August/112758.htmlhttps://pythonlang.de/pipermail/python-dev/2000-July/013243.html https://pythonlang.de/pipermail/python-dev/2000-July/013364.html https://pythonlang.de/pipermail/python-dev/2000-August/014940.html
Dies sind frühere Entwürfe dieses PEP
Es gibt einen alternativen PEP (offiziell PEP 211) von Greg Wilson mit dem Titel „Adding New Linear Algebra Operators to Python“.
Seine erste (und aktuelle) Version ist unter
Zusätzliche Referenzen
Quelle: https://github.com/python/peps/blob/main/peps/pep-0225.rst
Zuletzt geändert: 2024-04-14 20:08:31 GMT