Eine kurze Antwort: verwenden proxy_tools
Das proxy_toolsPaket versucht, @module_propertyFunktionen bereitzustellen .
Es wird mit installiert
pip install proxy_tools
Mit einer geringfügigen Modifikation von @ Mareins Beispiel the_module.pysetzen 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.thingist kein String ! Es ist ein proxy_tools.ProxyObjekt, 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_modulees sich um eine Instanz der types.ModuleTypeKlasse handelt. Das Festlegen einer "Moduleigenschaft" entspricht dem Festlegen einer Eigenschaft für eine Instanz dieser Klasse und nicht für die types.ModuleTypeKlasse selbst. Weitere Einzelheiten finden Sie in dieser Antwort .
Wir können Eigenschaften types.ModuleTypewie 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 .