PEP 3130 – Zugriff auf aktuelles Modul/Klasse/Funktion
- Autor:
- Jim J. Jewett <jimjjewett at gmail.com>
- Status:
- Abgelehnt
- Typ:
- Standards Track
- Erstellt:
- 22. April 2007
- Python-Version:
- 3.0
- Post-History:
- 22. April 2007
Ablehnungsbescheid
Dieser PEP wird abgelehnt. Es ist nicht klar, wie er implementiert werden sollte oder welche genauen Semantiken in Grenzfällen gelten sollten, und es gibt nicht genügend wichtige Anwendungsfälle. Die Resonanz war bestenfalls verhalten.
Zusammenfassung
Es ist üblich, eine Referenz auf das aktuelle Modul, die aktuelle Klasse oder die aktuelle Funktion zu benötigen, aber es gibt derzeit keinen absolut korrekten Weg, dies zu tun. Dieser PEP schlägt die Einführung der Schlüsselwörter __module__, __class__ und __function__ vor.
Begründung für __module__
Viele Module exportieren verschiedene Funktionen, Klassen und andere Objekte, führen aber zusätzliche Aktivitäten durch (wie z.B. das Ausführen von Unit-Tests), wenn sie als Skript ausgeführt werden. Die aktuelle Methode besteht darin, zu prüfen, ob der Name des Moduls auf einen magischen Wert gesetzt wurde.
if __name__ == "__main__": ...
Komplexere Introspektion erfordert, dass ein Modul versucht, sich selbst zu importieren. Wenn der Import des erwarteten Namens tatsächlich ein anderes Modul ergibt, gibt es keine gute Ausweichlösung.
# __import__ lets you use a variable, but... it gets more
# complicated if the module is in a package.
__import__(__name__)
# So just go to sys modules... and hope that the module wasn't
# hidden/removed (perhaps for security), that __name__ wasn't
# changed, and definitely hope that no other module with the
# same name is now available.
class X(object):
pass
import sys
mod = sys.modules[__name__]
mod = sys.modules[X.__class__.__module__]
Vorschlag: Füge ein Schlüsselwort __module__ hinzu, das sich auf das aktuell definierte (ausgeführte) Modul bezieht. (Siehe aber offene Punkte.)
# XXX sys.main is still changing as draft progresses. May
# really need sys.modules[sys.main]
if __module__ is sys.main: # assumes PEP (3122), Cannon
...
Begründung für __class__
Klassenmethoden wird die aktuelle Instanz übergeben; daraus können sie self.__class__ (oder cls, bei Klassenmethoden) ermitteln. Leider ist diese Referenz auf die tatsächliche Klasse des Objekts bezogen, die eine Unterklasse der definierenden Klasse sein kann. Die aktuelle Ausweichlösung besteht darin, den Namen der Klasse zu wiederholen und davon auszugehen, dass der Name nicht neu zugewiesen wird.
class C(B):
def meth(self):
super(C, self).meth() # Hope C is never rebound.
class D(C):
def meth(self):
# ?!? issubclass(D,C), so it "works":
super(C, self).meth()
Vorschlag: Füge ein Schlüsselwort __class__ hinzu, das sich auf die aktuell definierte (ausgeführte) Klasse bezieht. (Siehe aber offene Punkte.)
class C(B):
def meth(self):
super(__class__, self).meth()
Beachte, dass `super`-Aufrufe durch den PEP "New Super" (Spealman) weiter vereinfacht werden können. Das Attribut __class__ (oder __this_class__) kam bei Versuchen auf, die Erklärung und/oder Implementierung dieses PEPs zu vereinfachen, wurde aber als eigenständige Entscheidung abgetrennt.
Beachte, dass __class__ (oder __this_class__) nicht ganz dasselbe ist wie die Eigenschaft __thisclass__ auf gebundenen Super-Objekten. Die bestehende Eigenschaft super.__thisclass__ bezieht sich auf die Klasse, von der die Suche in der Method Resolution Order (MRO) beginnt. In der obigen Klasse D würde sie sich auf (die aktuelle Referenz auf den Namen) C beziehen.
Begründung für __function__
Funktionen (einschließlich Methoden) möchten oft Zugriff auf sich selbst haben, normalerweise für einen privaten Speicherort oder zur echten Rekursion. Obwohl es mehrere Ausweichlösungen gibt, haben alle ihre Nachteile.
def counter(_total=[0]):
# _total shouldn't really appear in the
# signature at all; the list wrapping and
# [0] unwrapping obscure the code
_total[0] += 1
return _total[0]
@annotate(total=0)
def counter():
# Assume name counter is never rebound:
counter.total += 1
return counter.total
# class exists only to provide storage:
class _wrap(object):
__total = 0
def f(self):
self.__total += 1
return self.__total
# set module attribute to a bound method:
accum = _wrap().f
# This function calls "factorial", which should be itself --
# but the same programming styles that use heavy recursion
# often have a greater willingness to rebind function names.
def factorial(n):
return (n * factorial(n-1) if n else 1)
Vorschlag: Füge ein Schlüsselwort __function__ hinzu, das sich auf die aktuell definierte (ausgeführte) Funktion (oder Methode) bezieht. (Siehe aber offene Punkte.)
@annotate(total=0)
def counter():
# Always refers to this function obj:
__function__.total += 1
return __function__.total
def factorial(n):
return (n * __function__(n-1) if n else 1)
Abwärtskompatibilität
Obwohl ein Benutzer diese Namen bereits verwenden könnte, sind doppelte Unterstrichenamen (__irgendwas__) ausdrücklich für den Interpreter reserviert. Daher ist es akzeptabel, diesen Namen innerhalb einer einzigen Feature-Version eine besondere Bedeutung zuzuweisen.
Implementierung
Idealerweise wären diese Namen Schlüsselwörter, die vom Bytecode-Compiler speziell behandelt werden.
Guido hat [1] die Verwendung einer Zellvariablen vorgeschlagen, die von der Metaklasse gefüllt wird.
Michele Simionato hat einen Prototyp mit Bytecode-Hacks [2] bereitgestellt. Dies erfordert keine neuen Bytecode-Operatoren; es modifiziert nur, welche spezifische Sequenz von vorhandenen Operatoren ausgeführt wird.
Offene Fragen
- Sind
__module__,__class__und__function__die richtigen Namen? Insbesondere sollten die Namen das Wort "this" enthalten, entweder als__this_module__,__this_class__und__this_function__(Format diskutiert in den Listen python-3000 und python-ideas) oder als__thismodule__,__thisclass__und__thisfunction__(inspiriert von, aber im Konflikt mit, der aktuellen Verwendung von super.``__thisclass__``). - Werden alle drei Schlüsselwörter benötigt oder sollte diese Erweiterung auf eine Teilmenge der Objekte beschränkt werden? Sollten Methoden separat von anderen Funktionen behandelt werden?
Referenzen
Urheberrecht
Dieses Dokument wurde gemeinfrei erklärt.
Quelle: https://github.com/python/peps/blob/main/peps/pep-3130.rst
Zuletzt geändert: 2025-02-01 08:59:27 GMT