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

Python Enhancement Proposals

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

Inhaltsverzeichnis

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


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

Zuletzt geändert: 2025-02-01 08:59:27 GMT