Es gibt zwei grundlegende Probleme, auf die Sie hier stoßen:
__xxx__
Methoden werden nur in der Klasse nachgeschlagen
TypeError: can't set attributes of built-in/extension type 'module'
(1) bedeutet, dass jede Lösung auch verfolgen muss, welches Modul untersucht wird, andernfalls würde jedes Modul dann das Instanzersetzungsverhalten aufweisen; und (2) bedeutet, dass (1) nicht einmal möglich ist ... zumindest nicht direkt.
Glücklicherweise ist sys.modules nicht wählerisch, was dort vor sich geht, damit ein Wrapper funktioniert, sondern nur für import somemodule; somemodule.salutation('world')
den Modulzugriff (dh für den Zugriff auf dasselbe Modul müssen Sie die Methoden aus der Substitutionsklasse ziehen und sie globals()
mit einem zu einem hinzufügen Benutzerdefinierte Methode für die Klasse (die ich gerne verwende .export()
) oder mit einer generischen Funktion (wie die bereits als Antworten aufgeführten). Beachten Sie Folgendes: Wenn der Wrapper jedes Mal eine neue Instanz erstellt und die globale Lösung nicht. Sie haben am Ende ein subtil anderes Verhalten. Oh, und Sie können nicht beide gleichzeitig verwenden - es ist das eine oder andere.
Aktualisieren
Von Guido van Rossum :
Es gibt tatsächlich einen Hack, der gelegentlich verwendet und empfohlen wird: Ein Modul kann eine Klasse mit der gewünschten Funktionalität definieren und sich am Ende in sys.modules durch eine Instanz dieser Klasse ersetzen (oder durch die Klasse, wenn Sie darauf bestehen , aber das ist im Allgemeinen weniger nützlich). Z.B:
# module foo.py
import sys
class Foo:
def funct1(self, <args>): <code>
def funct2(self, <args>): <code>
sys.modules[__name__] = Foo()
Dies funktioniert, weil die Importmaschinerie diesen Hack aktiv aktiviert und als letzten Schritt das eigentliche Modul nach dem Laden aus sys.modules herauszieht. (Dies ist kein Zufall. Der Hack wurde vor langer Zeit vorgeschlagen und wir entschieden, dass wir genug mochten, um ihn in den Importmaschinen zu unterstützen.)
Der etablierte Weg, um das zu erreichen, was Sie wollen, besteht darin, eine einzelne Klasse in Ihrem Modul zu erstellen und als letzten Akt des Moduls durch sys.modules[__name__]
eine Instanz Ihrer Klasse zu ersetzen - und jetzt können Sie nach Bedarf mit __getattr__
/ __setattr__
/ spielen __getattribute__
.
Hinweis 1 : Wenn Sie diese Funktionalität verwenden, gehen alle anderen Elemente des Moduls, wie z. B. Globals, andere Funktionen usw., bei der sys.modules
Zuweisung verloren. Stellen Sie daher sicher, dass sich alle erforderlichen Elemente in der Ersatzklasse befinden .
Hinweis 2 : Zur Unterstützung from module import *
müssen Sie __all__
in der Klasse definiert haben . beispielsweise:
class Foo:
def funct1(self, <args>): <code>
def funct2(self, <args>): <code>
__all__ = list(set(vars().keys()) - {'__module__', '__qualname__'})
Abhängig von Ihrer Python-Version können andere Namen weggelassen werden __all__
. Dies set()
kann weggelassen werden, wenn keine Python 2-Kompatibilität erforderlich ist.