PEP 549 – Instanzdeskriptoren
- Autor:
- Larry Hastings <larry at hastings.org>
- Discussions-To:
- Python-Dev Liste
- Status:
- Abgelehnt
- Typ:
- Standards Track
- Erstellt:
- 04. September 2017
- Python-Version:
- 3.7
- Post-History:
- 04. September 2017
Inhaltsverzeichnis
Ablehnungsbescheid
https://mail.python.org/pipermail/python-dev/2017-November/150528.html
Zusammenfassung
Pythons Deskriptorprotokoll verlangt, dass Deskriptoren Mitglieder des Typs eines Objekts sind. Diese PEP schlägt eine Erweiterung des Deskriptorprotokolls vor, die die Verwendung des Deskriptorprotokolls für Mitglieder von Instanzen erlaubt. Dies würde die Verwendung von Eigenschaften in Modulen ermöglichen.
Begründung
Pythons Deskriptorprotokoll leitet Programmierer zu einem eleganten API-Design an. Wenn Ihre Klasse ein datenähnliches Mitglied unterstützt und Sie eines Tages vielleicht Code ausführen müssen, wenn sich der Wert des Mitglieds ändert, werden Sie ermutigt, es vorerst einfach als einfaches Datenmitglied der Klasse zu deklarieren. Wenn Sie in Zukunft Code ausführen müssen, können Sie es in eine „Eigenschaft“ ändern, und glücklicherweise ändert sich die API nicht.
Betrachten Sie jedoch diesen zweiten Punkt des bewährten Python-API-Designs: Wenn Sie einen Singleton schreiben, schreiben Sie keine Klasse, sondern bauen Sie Ihren Code direkt in ein Modul ein. Lassen Sie Ihre Benutzer keine Singleton-Klasse instanziieren, lassen Sie Ihre Benutzer nicht über ein in einem Modul gespeichertes Singleton-Objekt dereferenzieren, sondern haben Sie einfach Funktionen auf Modulebene und Daten auf Modulebene.
Leider stehen diese beiden bewährten Vorgehensweisen im Widerspruch zueinander. Das Problem ist, dass Eigenschaften für Module nicht unterstützt werden. Module sind Instanzen eines einzelnen generischen module-Typs, und es ist nicht machbar, diesen Typ zu ändern oder zu unterklassieren, um einer Eigenschaft für sein Modul hinzuzufügen. Das bedeutet, dass Programmierer, die mit dieser API-Designentscheidung konfrontiert sind, bei der das datenähnliche Mitglied ein Singleton ist, das in einem Modul gespeichert ist, im Voraus hässliche „Getter“ und „Setter“ für die Daten hinzufügen müssen.
Das Hinzufügen von Unterstützung für Moduleigenschaften in reinem Python ist kürzlich möglich geworden; ab Python 3.5 erlaubt Python Zuweisungen zum __class__-Attribut von Modulobjekten, speziell zu diesem Zweck. Hier ist ein Beispiel für die Verwendung dieser Funktionalität, um einem Modul eine Eigenschaft hinzuzufügen
import sys, types
class _MyModuleType(types.ModuleType):
@property
def prop(self, instance, owner):
...
sys.modules[__name__].__class__ = _MyModuleType
Dies funktioniert und ist unterstütztes Verhalten, aber es ist umständlich und obskur.
Diese PEP schlägt eine typspezifische Opt-in-Erweiterung des Deskriptorprotokolls vor, die speziell für die Aktivierung von Eigenschaften in Modulen entwickelt wurde. Der Mechanismus ist eine Möglichkeit, das Deskriptorprotokoll für Mitglieder von Instanzen einer Klasse zu ehren, ohne dass das Mitglied als Klassenvariable deklariert ist.
Obwohl dies als allgemeiner Mechanismus vorgeschlagen wird, sieht der Autor derzeit nur eine Nützlichkeit für Modulobjekte.
Implementierung
Die Grundidee ist einfach: Modifizieren Sie die tp_descr_get und tp_descr_set Funktionen, die von PyModule_Type bereitgestellt werden, um das Attribut zu inspizieren, mit dem interagiert wird, und wenn es das Deskriptorprotokoll unterstützt, rufen Sie die relevante bereitgestellte Funktion auf.
Unsere Implementierung steht vor zwei Herausforderungen
- Da dieser Code jedes Mal ausgeführt wird, wenn ein Attribut auf einer Methode nachgeschlagen wird, muss er im allgemeinen Fall, in dem das in dem Attribut gespeicherte Objekt kein Deskriptor ist, nur sehr geringe zusätzliche Kosten verursachen.
- Da Funktionen Deskriptoren sind, müssen wir darauf achten, das Deskriptorprotokoll nicht für alle Objekte zu ehren. Andernfalls würden alle Funktionen auf Modulebene plötzlich an die Modulinstanz gebunden, als wären sie Methodenaufrufe auf dem Modulobjekt. Das Modulhandle würde als „self“-Argument an alle Funktionen auf Modulebene übergeben.
Beide Herausforderungen können mit demselben Ansatz gelöst werden: Wir definieren ein neues „Fast Subclass“-Flag, das bedeutet: „Dieses Objekt ist ein Deskriptor und sollte direkt honoriert werden, wenn dieses Objekt als Attribut einer Instanz nachgeschlagen wird“. Bisher ist dieses Flag nur auf zwei Typen gesetzt: property und collections.abc.InstanceDescriptor. Letzteres ist eine abstrakte Basisklasse, deren einziger Zweck darin besteht, es Benutzerklassen zu ermöglichen, dieses „Fast Subclass“-Flag zu erben.
Prototyp
Ein Prototyp dieser Funktionalität wird auf GitHub entwickelt [github].
Danksagungen
Armin Rigo schlug diesen Mechanismus im Wesentlichen vor, als ihm die Idee der „Moduleigenschaften“ vorgestellt wurde, und unterrichtete den Autor sowohl über die Komplexitäten des Problems als auch über die richtige Lösung. Nathaniel J. Smith wies auf die 3.5-Erweiterung zum Zuweisen von __class__ zu Modulobjekten hin und stellte das Beispiel bereit.
Referenzen
- Der Branch ist hier
- https://github.com/larryhastings/cpython/tree/module-properties
- Ein Pull-Request gegen das Haupt-CPython-Repository ist hier
- https://github.com/python/cpython/pull/3534
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-0549.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT