Una respuesta corta: usa proxy_tools
El proxy_tools
paquete intenta proporcionar @module_property
funcionalidad.
Se instala con
pip install proxy_tools
Utilizando una ligera modificación del ejemplo de @ Marein, the_module.py
ponemos
from proxy_tools import module_property
@module_property
def thing():
print(". ", end='') # Prints ". " on each invocation
return 'hello'
Ahora de otro guión, puedo hacer
import the_module
print(the_module.thing)
# . hello
Comportamiento inesperado
Esta solución no está exenta de salvedades. Es decir, ¡ nothe_module.thing
es una cadena ! Es un proxy_tools.Proxy
objeto cuyos métodos especiales se han anulado para que imite una cadena. Aquí hay algunas pruebas básicas que ilustran el punto:
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']
Internamente, la función original se almacena en the_module.thing._Proxy__local
:
print(res._Proxy__local)
# <function thing at 0x7f729c3bf680>
Pensamientos adicionales
Honestamente, estoy desconcertado acerca de por qué los módulos no tienen esta funcionalidad incorporada. Creo que el quid del asunto es que the_module
es una instancia de la types.ModuleType
clase. Establecer una "propiedad de módulo" equivale a establecer una propiedad en una instancia de esta clase, en lugar de en la types.ModuleType
clase misma. Para obtener más detalles, consulte esta respuesta .
De hecho, podemos implementar propiedades de la types.ModuleType
siguiente manera, aunque los resultados no son excelentes. No podemos modificar directamente los tipos integrados, pero podemos maldecirlos :
# 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__}'))
Esto nos da una propiedad que existe en todos los módulos. Es un poco difícil de manejar, ya que rompemos el comportamiento de configuración en todos los módulos:
import sys
print(sys.thing2)
# hi from sys
sys.thing2 = 5
# AttributeError: can't set attribute
__getattr__
un módulo para obtener una solución más moderna.