PEP 640 – Syntax für ungenutzte Variablen
- Autor:
- Thomas Wouters <thomas at python.org>
- Status:
- Abgelehnt
- Typ:
- Standards Track
- Erstellt:
- 04-Okt-2020
- Python-Version:
- 3.10
- Post-History:
- 19-Okt-2020
- Resolution:
- Python-Dev Nachricht
Ablehnungsnotiz
Von Rat abgelehnt: https://mail.python.org/archives/list/python-dev@python.org/message/SQC2FTLFV5A7DV7RCEAR2I2IKJKGK7W3/
Zusammenfassung
Dieses PEP schlägt eine neue Syntax für ungenutzte Variablen vor, die einen Pseudonamen bereitstellt, dem zugewiesen werden kann, aber der anderweitig nicht verwendet werden kann. Die Zuweisung findet tatsächlich nicht statt, und der Wert wird stattdessen verworfen.
Motivation
In Python ist es ziemlich üblich, eine Zuweisung vorzunehmen, ohne das Ergebnis tatsächlich zu benötigen. Konventionell verwenden Leute entweder "_" oder einen Namen wie "unused" (oder mit "unused" als Präfix) dafür. Dies ist am häufigsten bei Entpackungszuweisungen
x, unused, z = range(3)
x, *unused, z = range(10)
Es wird auch in for Schleifen und Comprehensions verwendet
for unused in range(10): ...
[ SpamObject() for unused in range(10) ]
Die Verwendung von "_" in diesen Fällen ist wahrscheinlich die häufigste, aber sie steht potenziell im Konflikt mit der Verwendung von "_" in der Internationalisierung, wo ein Aufruf wie gettext.gettext() an "_" gebunden wird und zur Markierung von Strings für die Übersetzung verwendet wird.
In dem Vorschlag zur Ergänzung von Pattern Matching zu Python (ursprünglich PEP 622, jetzt aufgeteilt in PEP 634, PEP 635 und PEP 636) hat "_" eine zusätzliche Sonderbedeutung. Es ist ein Wildcard-Muster, das an Stellen verwendet wird, an denen Variablen zugewiesen werden könnten, um anzuzeigen, dass etwas übereinstimmen soll, aber nichts zugewiesen werden soll. Die Wahl von "_" dort entspricht der Verwendung von "_" in anderen Sprachen, aber der semantische Unterschied zu "_" an anderer Stelle in Python ist signifikant.
Dieses PEP schlägt vor, ein spezielles Token, "?", anstelle jedes gültigen Namens in der Zuweisung zuzulassen. Dies hat die meisten Vorteile von "_", ohne andere Verwendungen dieser ansonsten regulären Variablen zu beeinträchtigen. Die Zulassung der Verwendung desselben Wildcard-Musters würde Pattern Matching und Entpackungszuweisungen konsistenter miteinander machen.
Begründung
Das Markieren bestimmter Variablen als ungenutzt ist ein nützliches Werkzeug, da es die Klarheit des Zwecks des Codes verbessert. Es macht für Leser des Codes sowie für automatisierte Linter offensichtlich, dass eine bestimmte Variable absichtlich ungenutzt ist.
Trotz der Konvention ist "_" keine spezielle Variable. Der Wert wird immer noch zugewiesen, das Objekt, auf das er verweist, wird bis zum Ende des Geltungsbereichs am Leben erhalten und es kann immer noch verwendet werden. Auch die Verwendung von "_" für ungenutzte Variablen ist nicht allgegenwärtig, da sie mit der konventionellen Internationalisierung kollidiert, nicht offensichtlich ist, dass es sich um eine reguläre Variable handelt, und nicht so offensichtlich ungenutzt ist wie eine Variable namens "unused".
Im Pattern Matching Vorschlag werden die Probleme von "_" für ungenutzte Variablen durch die Tatsache, dass es sich in einem separaten Geltungsbereich befindet, umgangen. Der einzige Konflikt, den es mit der Internationalisierung hat, ist einer der potenziellen Verwirrung, es wird nicht tatsächlich mit Verwendungen einer globalen Variable namens "_" interagieren. Die Sonderbehandlung von "_" für diesen Wildcard-Musterzweck ist jedoch immer noch problematisch: Die unterschiedlichen Semantiken und Bedeutungen von "_" innerhalb von Pattern Matching und außerhalb davon bedeuten einen Bruch der Konsistenz in Python.
Die Einführung von "?" als spezielle Syntax für ungenutzte Variablen sowohl innerhalb als auch außerhalb von Pattern Matching ermöglicht es uns, diese Konsistenz zu wahren. Sie vermeidet den Konflikt mit der Internationalisierung oder anderen Verwendungen von _ als Variable. Sie lässt Entpackungszuweisungen besser mit Pattern Matching übereinstimmen, was es einfacher macht, Pattern Matching als Erweiterung der Entpackungszuweisung zu erklären.
Hinsichtlich der Lesbarkeit des Codes erleichtert die Verwendung eines speziellen Tokens das Verständnis seiner Bedeutung ("was macht Fragezeichen in Python" vs. "warum wird meine _ Variable nicht zugewiesen") und macht offensichtlicher, dass die eigentliche Absicht ist, dass der Wert ungenutzt bleibt – da er gänzlich unmöglich zu verwenden ist.
Spezifikation
Ein neues Token wird eingeführt, "?", oder token.QMARK.
Die Grammatik wird modifiziert, um "?" in Zuweisungskontexten (star_atom und t_atom in der aktuellen Grammatik) zuzulassen und dabei einen Name AST-Knoten mit NULL als Bezeichner zu erstellen.
Der AST wird modifiziert, um den Bezeichner des Name Ausdrucks optional zu machen (er ist derzeit erforderlich). Das Leeren des Bezeichners wäre nur in einem STORE Kontext erlaubt.
In CPython wird der Bytecode-Compiler modifiziert, um POP_TOP anstelle von STORE_NAME für Name Knoten ohne Bezeichner auszugeben. Andere Verwendungen des Name Knotens werden entsprechend aktualisiert, um die leere Bezeichnerbehandlung zu unterstützen.
Die Verwendungen der modifizierten Grammatik-Knoten umfassen mindestens die folgenden Zuweisungsformen
? = ...
x, ?, z = ...
x, *?, z = ...
for ? in range(3): ... # including comprehension forms
for x, ?, z in matrix: ... # including comprehension forms
with open(f) as ?: ...
with func() as (x, ?, z): ...
Die Verwendung eines einzelnen "?", nicht in einem Entpackungskontext, ist bei normalen Zuweisungen und in with-Anweisungen zulässig. Es ergibt alleine nicht wirklich Sinn und es ist möglich, diese spezifischen Fälle zu verbieten. Allerdings hat for ? in range(3) eindeutig seinen Nutzen, daher erscheint es aus Gründen der Konsistenz, wenn nichts anderes, sinnvoller, die Verwendung des einzelnen "?" in anderen Fällen zuzulassen.
Die Verwendung von "?" in augmentierten Zuweisungen (? *= 2) ist nicht erlaubt, da "?" nur für Zuweisungen verwendet werden kann. Mehrere Vorkommen von "?" sind gültig, genau wie bei der Zuweisung an Namen, und die Zuweisungen beeinträchtigen sich nicht gegenseitig.
Abwärtskompatibilität
Die Einführung eines neuen Tokens bedeutet, dass es keine Probleme mit der Rückwärtskompatibilität gibt. Keine gültige Syntax ändert ihre Bedeutung.
"?" wird nicht als Bezeichner betrachtet, daher ändert sich str.isidentifier() nicht.
Der AST ändert sich auf inkompatible Weise, da der Bezeichner eines Name-Tokens jetzt leer sein kann. Code, der den AST verwendet, muss entsprechend angepasst werden.
Wie man das lehrt
"?" kann zusammen mit der Entpackungszuweisung eingeführt werden, indem erklärt wird, dass es sich um eine spezielle Syntax für „ungenutzt“ handelt, und erwähnt wird, dass es auch an anderen Stellen verwendet werden kann. Alternativ könnte es als Teil einer Erklärung zur Zuweisung in for-Schleifen eingeführt werden, wobei ein Beispiel gezeigt wird, bei dem die Schleifenvariable ungenutzt ist.
PEP 636 diskutiert, wie "_" unterrichtet wird, und kann einfach "_" durch "?" ersetzen, vielleicht mit dem Hinweis, dass "?" in anderen Kontexten ähnlich verwendbar ist.
Referenzimplementierung
Eine Prototypimplementierung existiert unter <https://github.com/Yhg1s/cpython/tree/nonassign>.
Abgelehnte Ideen
Offene Fragen
Sollte "?" in den folgenden Kontexten zulässig sein
# imports done for side-effect only.
import os as ?
from os import path as ?
# Function defined for side-effects only (e.g. decorators)
@register_my_func
def ?(...): ...
# Class defined for side-effects only (e.g. decorators, __init_subclass__)
class ?(...): ...
# Parameters defined for unused positional-only arguments:
def f(a, ?, ?): ...
lambda a, ?, ?: ...
# Unused variables with type annotations:
?: int = f()
# Exception handling:
try: ...
except Exception as ?: ...
# With blocks:
with open(f) as ?: ...
Einige dieser Punkte mögen aus Gründen der Konsistenz sinnvoll erscheinen, aber praktische Anwendungen sind begrenzt und fragwürdig. Typ-Annotationen auf "?" und die Verwendung mit except und with scheinen keinen Sinn zu ergeben. In der Referenzimplementierung wird except nicht unterstützt (die bestehende Syntax erlaubt nur einen Namen), aber with wird unterstützt (aufgrund der bestehenden Syntax, die Entpackungszuweisungen unterstützt).
Sollte dieses PEP akzeptiert werden, auch wenn Pattern Matching abgelehnt wird?
Urheberrecht
Dieses Dokument wird in die Public Domain oder unter die CC0-1.0-Universal-Lizenz gestellt, je nachdem, welche Lizenz permissiver ist.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0640.rst
Zuletzt geändert: 2025-02-01 08:55:40 GMT