Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python Enhancement Proposals

PEP 211 – Einführung eines neuen Operators für das äußere Produkt

Autor:
Greg Wilson <gvwilson at ddj.com>
Status:
Abgelehnt
Typ:
Standards Track
Erstellt:
15-Jul-2000
Python-Version:
2.1
Post-History:


Inhaltsverzeichnis

Warnung

Dieser PEP wurde abgelehnt.

×

Der Ansatz in der späteren PEP 465 wurde schließlich anstelle dieser PEP akzeptiert. Die Abgelehnte Ideen dieser PEP erläutern die Begründung detaillierter.

Einleitung

Diese PEP beschreibt einen Vorschlag, @ (ausgesprochen „across“) als neuen Operator für das äußere Produkt in Python 2.2 zu definieren. Wenn er auf Sequenzen (oder andere iterierbare Objekte) angewendet wird, kombiniert dieser Operator ihre Iteratoren, so dass

for (i, j) in S @ T:
    pass

gleichwertig sein wird mit

for i in S:
    for j in T:
        pass

Klassen werden in der Lage sein, diesen Operator über die speziellen Methoden __across__, __racross__ und __iacross__ zu überladen. Insbesondere wird das neue Numeric-Modul (PEP 209) diesen Operator für mehrdimensionale Arrays überladen, um Matrixmultiplikation zu implementieren.

Hintergrund

Zahlenintensive Berechnungen sind nur ein kleiner Teil des Computings, aber viele Programmierer – einschließlich vieler Python-Benutzer – müssen immer noch komplexe mathematische Operationen im Code ausdrücken. Die meisten numerischen Sprachen wie APL, Fortran-90, MATLAB, IDL und Mathematica bieten daher zwei Formen der gängigen arithmetischen Operatoren. Eine Form arbeitet elementweise, multipliziert z. B. entsprechende Elemente ihrer Matrixargumente. Die andere implementiert die „mathematische“ Definition dieser Operation, z. B. führt sie eine Zeilen-Spalten-Matrixmultiplikation durch.

Zhu und Lielens haben vorgeschlagen, Pythons Operatoren auf diese Weise zu verdoppeln. Ihr Vorschlag würde sechs neue binäre Infix-Operatoren und sechs neue In-Place-Operatoren schaffen.

Die ursprüngliche Version dieses Vorschlags war wesentlich konservativer. Der Autor konsultierte die Entwickler von GNU Octave [1], einem Open-Source-Klon von MATLAB. Ihre Entwickler stimmten zu, dass die Bereitstellung eines Infix-Operators für die Matrixmultiplikation wichtig ist: Numerische Programmierer kümmern sich wirklich darum, ob sie mmul(A,B) anstelle von A op B schreiben müssen.

Auf der anderen Seite, als gefragt wurde, wie wichtig es sei, Infix-Operatoren für Matrixlösung und andere Operationen zu haben, antwortete Prof. James Rawlings [2]

Ich denke nicht, dass es ein Muss ist, und ich mache viel Matrixinversion. Ich kann mich nicht erinnern, ob es A\b oder b\A ist, also schreibe ich immer stattdessen inv(A)*b. Ich empfehle, \ fallen zu lassen.

Basierend auf dieser Diskussion und dem Feedback von Studenten an den US-National Laboren und anderswo empfahlen wir, nur einen neuen Operator für die Matrixmultiplikation zu Python hinzuzufügen.

Iterators

Die geplante Hinzufügung von Iteratoren zu Python 2.2 eröffnet einen breiteren Rahmen für diesen Vorschlag. Im Rahmen der Diskussion von PEP 201, Lockstep Iteration, führte der Autor dieses Vorschlags ein informelles Benutzbarkeitsexperiment durch [3]. Die Ergebnisse zeigten, dass Benutzer psychologisch empfänglich für die „Kreuzprodukt“-Schleifensyntax sind. Zum Beispiel erwarteten die meisten Benutzer, dass

S = [10, 20, 30]
T = [1, 2, 3]
for x in S; y in T:
    print x+y,

11 12 13 21 22 23 31 32 33 ausgeben wird. Wir glauben, dass Benutzer die gleiche Reaktion auf

for (x, y) in S @ T:
    print x+y

haben werden, d. h. dass sie dies natürlich als eine saubere Art und Weise interpretieren werden, Schleifennester zu schreiben.

Hier kommen Iteratoren ins Spiel. Tatsächlich das Kreuzprodukt von zwei (oder mehr) Sequenzen vor der Ausführung der Schleife zu konstruieren, wäre sehr teuer. Auf der anderen Seite könnte @ so definiert werden, dass es die Iteratoren seiner Argumente erhält und dann einen äußeren Iterator erstellt, der Tupel der von den inneren Iteratoren zurückgegebenen Werte liefert.

Diskussion

  1. Das Hinzufügen einer benannten Funktion „across“ hätte weniger Auswirkungen auf Python als ein neuer Infix-Operator. Dies würde Python jedoch für numerische Programmierer, denen es wirklich wichtig ist, ob sie Matrixmultiplikation mit einem Operator oder als Funktionsaufruf schreiben können, nicht attraktiver machen.
  2. @ müsste auf die gleiche Weise verknüpfbar sein wie Vergleichsoperatoren, d. h.
    (1, 2) @ (3, 4) @ (5, 6)
    

    (1, 3, 5) ... (2, 4, 6) zurückgeben, und *nicht* ((1, 3), 5) ... ((2, 4), 6). Dies sollte keine spezielle Unterstützung vom Parser erfordern, da der äußere Iterator, der vom ersten @ erstellt wurde, leicht lernen könnte, sich mit normalen Iteratoren zu kombinieren.

  3. Es müsste eine Möglichkeit geben, wiederanfangbare Iteratoren von solchen zu unterscheiden, die nicht wiederanfangbar sind. Wenn S beispielsweise ein Eingabestrom (z. B. eine Datei) ist und L eine Liste ist, dann ist S @ L einfach, aber L @ S nicht, da die Iteration durch den Strom nicht wiederholt werden kann. Dies könnte als Fehler behandelt werden, oder der äußere Iterator könnte nicht wiederanfangbare innere Iteratoren erkennen und deren Werte zwischenspeichern.
  4. Testen an einem Whiteboard dieses Vorschlags mit drei unerfahrenen Python-Benutzern (alle erfahrene Programmierer) zeigt, dass Benutzer erwarten würden, dass
    "ab" @ "cd"
    

    vier Strings zurückgegeben werden, nicht vier Tupel von Zeichenpaaren. Die Meinung war geteilt, was

    ("a", "b") @ "cd"
    

    zurückgeben sollte…

Alternativen

  1. Nichts tun – Python einfach halten.

    Dies ist immer die Standardwahl.

  2. Fügen Sie stattdessen eine benannte Funktion hinzu.

    Python ist keine primär numerische Sprache; es lohnt sich möglicherweise nicht, sie für diesen Sonderfall zu verkomplizieren. Die Unterstützung für echte Matrixmultiplikation wird jedoch *häufig* angefordert, und die vorgeschlagenen Semantiken für @ für integrierte Sequenztypen würden die Ausdrucksweise eines sehr gängigen Idioms (verschachtelte Schleifen) vereinfachen.

  3. Führen Sie präfixierte Formen aller bestehenden Operatoren ein, wie z. B. ~* und ~+, wie in PEP 225 vorgeschlagen.

    Unsere Einwände dagegen sind, dass die Nachfrage nicht ausreicht, um die zusätzliche Komplexität zu rechtfertigen (siehe Kommentare von Rawlings [2]), und dass die vorgeschlagene Syntax den „Low Toner“-Lesbarkeitstest nicht besteht.

Danksagungen

Ich bin Huaiyu Zhu dankbar für die Initiierung dieser Diskussion und James Rawlings und den Studenten in verschiedenen Python-Kursen für ihre Diskussionen darüber, was numerische Programmierer wirklich interessiert.

Referenzen


Quelle: https://github.com/python/peps/blob/main/peps/pep-0211.rst

Zuletzt geändert: 2024-04-14 20:08:31 GMT