Mit Python-Eigenschaften kann ich es so machen, dass
obj.y
ruft eine Funktion auf, anstatt nur einen Wert zurückzugeben.
Gibt es eine Möglichkeit, dies mit Modulen zu tun? Ich habe einen Fall, wo ich will
module.y
eine Funktion aufrufen, anstatt nur den dort gespeicherten Wert zurückzugeben.
python
properties
python-module
Josh Gibson
quelle
quelle
__getattr__
in einem Modul .Antworten:
Nur Instanzen von Klassen neuen Stils können Eigenschaften haben. Sie können Python glauben machen, dass eine solche Instanz ein Modul ist, indem Sie sie verstecken
sys.modules[thename] = theinstance
. So könnte Ihre m.py-Moduldatei beispielsweise sein:quelle
types.ModuleType
wie in der ansonsten sehr ähnlichen Antwort von @ Unknown gezeigt?builtins.module
, von denen selbst eine Instanz isttype
(was die Definition einer Klasse neuen Stils ist). Das Problem ist, dass Eigenschaften für die Klasse und nicht für die Instanz vorliegen müssen. Wenn Sie dies tunf = Foo()
,f.some_property = property(...)
schlägt dies genauso fehl, als ob Sie es naiv in ein Modul einfügen. Die Lösung besteht darin, es in die Klasse einzufügen. Da jedoch nicht alle Module die Eigenschaft haben sollen, wird eine Unterklasse erstellt (siehe Antwort von Unknown).globals()
(die Schlüssel intakt halten, aber die Werte auf zurücksetzenNone
) beim erneuten Binden des Namenssys.modules
ist ein Python 2-Problem - Python 3.4 funktioniert wie beabsichtigt. Wenn Sie Zugriff auf das Klassenobjekt in Py2 benötigen, fügen Sie z. B._M._cls = _M
direkt nach derclass
Anweisung hinzu (oder speichern Sie es äquivalent in einem anderen Namespace) und greifen Sie darauf zu, wieself._cls
in den Methoden, die dies erfordern (type(self)
möglicherweise in Ordnung, aber nicht, wenn Sie auch eine Unterklasse von ausführen_M
). .Ich würde dies tun, um alle Attribute eines Moduls richtig zu erben und durch isinstance () korrekt identifiziert zu werden.
Und dann können Sie dies in sys.modules einfügen:
quelle
__file__
, die manuell definiert werden müssen. (2) Im Modul, das die Klasse enthält, vorgenommene Importe werden zur Laufzeit nicht "sichtbar" usw.types.ModuleType
, jede (neuem Stil) Klasse tun wird. Welche speziellen Modulattribute möchten Sie erben?__init__
einer Instanz angeben und Sie erhalten ein korrektes Verhalten bei der Verwendungisinstance
.Da PEP 562 in Python> = 3.7 implementiert wurde, können wir dies jetzt tun
Datei: module.py
Verwendung:
Beachten Sie, dass, wenn Sie das
raise AttributeError
in der__getattr__
Funktion weglassen , dies bedeutet, dass die Funktion mit endetreturn None
und dasmodule.nosuch
einen Wert von erhältNone
.quelle
Basierend auf John Lins Antwort :
Verwendung (beachten Sie den führenden Unterstrich), in
the_module.py
:Dann:
Der führende Unterstrich ist erforderlich, um die eigenschaftsbezogene Funktion von der ursprünglichen Funktion zu unterscheiden. Ich konnte mir keine Möglichkeit vorstellen, die Kennung neu zuzuweisen, da sie während der Ausführung des Dekorateurs noch nicht zugewiesen wurde.
Beachten Sie, dass IDEs nicht wissen, dass die Eigenschaft vorhanden ist, und rote Wellen anzeigen.
quelle
@property def x(self): return self._x
halte ich esdef thing()
ohne Unterstrich für konventioneller. Und können Sie in Ihrer Antwort auch einen Dekorator für "Module Property Setter" erstellen?def thing()
Vorschlag umzusetzen . Problem ist, dass__getattr__
nur für fehlende Attribute aufgerufen wird . Aber nach@module_property def thing(): …
Läufenthe_module.thing
ist definiert, so dass getattr nie aufgerufen wird. Wir müssen uns irgendwiething
im Dekorator registrieren und ihn dann aus dem Namespace des Moduls löschen. Ich habe versucht,None
vom Dekorateur zurückzukehren, aber dannthing
ist definiert alsNone
. Man könnte es tun,@module_property def thing(): … del thing
aber ich finde das schlimmer alsthing()
als Funktion zu verwenden__getattribute__
". Danke dir.Ein typischer Anwendungsfall ist: Anreichern eines (riesigen) vorhandenen Moduls mit einigen (wenigen) dynamischen Attributen - ohne das gesamte Modulmaterial in ein Klassenlayout umzuwandeln. Leider
sys.modules[__name__].__class__ = MyPropertyModule
schlägt ein einfachster Modulklassen-Patch wie fehlTypeError: __class__ assignment: only for heap types
. Daher muss die Modulerstellung neu verkabelt werden.Dieser Ansatz macht es ohne Python-Import-Hooks, nur indem ein Prolog über dem Modulcode steht:
Verwendung:
Hinweis: So etwas
from propertymodule import dynval
erzeugt natürlich eine eingefrorene Kopie - entsprechenddynval = someobject.dynval
quelle
Eine kurze Antwort: verwenden
proxy_tools
Das
proxy_tools
Paket versucht,@module_property
Funktionen bereitzustellen .Es wird mit installiert
Mit einer geringfügigen Modifikation von @ Mareins Beispiel
the_module.py
setzen wir einJetzt aus einem anderen Skript kann ich tun
Unerwartetes Verhalten
Diese Lösung ist nicht ohne Einschränkungen. Das heißt,
the_module.thing
ist kein String ! Es ist einproxy_tools.Proxy
Objekt, dessen spezielle Methoden überschrieben wurden, damit es eine Zeichenfolge nachahmt. Hier sind einige grundlegende Tests, die den Punkt veranschaulichen:Intern wird die ursprüngliche Funktion gespeichert in
the_module.thing._Proxy__local
:Weitere Gedanken
Ehrlich gesagt bin ich verblüfft darüber, warum Module diese Funktionalität nicht eingebaut haben. Ich denke, der springende Punkt ist, dass
the_module
es sich um eine Instanz dertypes.ModuleType
Klasse handelt. Das Festlegen einer "Moduleigenschaft" entspricht dem Festlegen einer Eigenschaft für eine Instanz dieser Klasse und nicht für dietypes.ModuleType
Klasse selbst. Weitere Einzelheiten finden Sie in dieser Antwort .Wir können Eigenschaften
types.ModuleType
wie folgt implementieren , obwohl die Ergebnisse nicht großartig sind. Wir können eingebaute Typen nicht direkt ändern, aber wir können sie verfluchen :Dies gibt uns eine Eigenschaft, die über alle Module existiert. Es ist etwas unhandlich, da wir das Einstellungsverhalten über alle Module hinweg aufteilen:
quelle
@module_property
Dekorateur. Im Allgemeinen wird der integrierte@property
Dekorator verwendet, wenn eine Klasse definiert wird, nicht nachdem eine Instanz erstellt wurde. Daher würde ich davon ausgehen, dass dies auch für eine Moduleigenschaft gilt, und dies gilt für Alex 'Antwort - erinnern Sie sich an diese Frage "Können Module Eigenschaften haben, die Objekte haben können?" Es ist jedoch möglich, sie später hinzuzufügen, und ich habe mein früheres Snippet geändert, um zu veranschaulichen, wie dies getan werden kann.cached_module_property
ist die Tatsache__getattr__()
hilfreich , dass nicht mehr aufgerufen wird, wenn das Attribut definiert wird. (ähnlich dem, wasfunctools.cached_property
erreicht wird).