Eine kurze Antwort: verwenden proxy_tools
Das proxy_tools
Paket versucht, @module_property
Funktionen bereitzustellen .
Es wird mit installiert
pip install proxy_tools
Mit einer geringfügigen Modifikation von @ Mareins Beispiel the_module.py
setzen wir ein
from proxy_tools import module_property
@module_property
def thing():
print(". ", end='') # Prints ". " on each invocation
return 'hello'
Jetzt aus einem anderen Skript kann ich tun
import the_module
print(the_module.thing)
# . hello
Unerwartetes Verhalten
Diese Lösung ist nicht ohne Einschränkungen. Das heißt, the_module.thing
ist kein String ! Es ist ein proxy_tools.Proxy
Objekt, dessen spezielle Methoden überschrieben wurden, damit es eine Zeichenfolge nachahmt. Hier sind einige grundlegende Tests, die den Punkt veranschaulichen:
res = the_module.thing
# [No output!!! Evaluation doesn't occur yet.]
print(type(res))
# <class 'proxy_tools.Proxy'>
print(isinstance(res, str))
# False
print(res)
# . hello
print(res + " there")
# . hello there
print(isinstance(res + "", str))
# . True
print(res.split('e'))
# . ['h', 'llo']
Intern wird die ursprüngliche Funktion gespeichert in the_module.thing._Proxy__local
:
print(res._Proxy__local)
# <function thing at 0x7f729c3bf680>
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 der types.ModuleType
Klasse handelt. Das Festlegen einer "Moduleigenschaft" entspricht dem Festlegen einer Eigenschaft für eine Instanz dieser Klasse und nicht für die types.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 :
# python -m pip install forbiddenfruit
from forbiddenfruit import curse
from types import ModuleType
# curse has the same signature as setattr.
curse(ModuleType, "thing2", property(lambda module: f'hi from {module.__name__}'))
Dies gibt uns eine Eigenschaft, die über alle Module existiert. Es ist etwas unhandlich, da wir das Einstellungsverhalten über alle Module hinweg aufteilen:
import sys
print(sys.thing2)
# hi from sys
sys.thing2 = 5
# AttributeError: can't set attribute
__getattr__
in einem Modul .