¿Pueden los módulos tener propiedades de la misma manera que los objetos?

Con las propiedades de python, puedo hacerlo de tal manera que

obj.y 

llama a una función en lugar de simplemente devolver un valor.

¿Hay alguna manera de hacer esto con los módulos? Tengo un caso donde quiero

 module.y 

para llamar a una función, en lugar de simplemente devolver el valor almacenado allí.

Solo las instancias de clases de nuevo estilo pueden tener propiedades. Puedes hacer que Python crea que tal instancia es un módulo sys.modules[thename] = theinstance en sys.modules[thename] = theinstance . Entonces, por ejemplo, su archivo de módulo m.py podría ser:

 import sys class _M(object): def __init__(self): self.c = 0 def afunction(self): self.c += 1 return self.c y = property(afunction) sys.modules[__name__] = _M() 

Haría esto para heredar correctamente todos los atributos de un módulo, y ser identificado correctamente por isinstance ()

 import types class MyModule(types.ModuleType): @property def y(self): return 5 >>> a=MyModule("test") >>> a  >>> ay 5 

Y luego puede insertar esto en sys.modules:

 sys.modules[__name__] = MyModule(__name__) # remember to instantiate the class 

Un caso de uso típico es: enriquecer un (enorme) módulo existente con algunos (pocos) atributos dynamics, sin convertir todo el material del módulo en un diseño de clase. Desafortunadamente, un parche de clase de módulo más simple como sys.modules[__name__].__class__ = MyPropertyModule falla con TypeError: __class__ assignment: only for heap types . Por lo tanto, la creación del módulo debe ser reconfigurada.

Este enfoque lo hace sin los enlaces de importación de Python, solo por tener un prólogo sobre el código del módulo:

 # propertymodule.py """ Module property example """ if '__orgmod__' not in globals(): # constant prolog for having module properties / supports reload() print "PropertyModule stub execution", __name__ import sys, types class PropertyModule(types.ModuleType): def __str__(self): return "" % (self.__name__, self.__file__) modnew = PropertyModule(__name__, __doc__) modnew.__modclass__ = PropertyModule modnew.__file__ = __file__ modnew.__orgmod__ = sys.modules[__name__] sys.modules[__name__] = modnew exec sys._getframe().f_code in modnew.__dict__ else: # normal module code (usually vast) .. print "regular module execution" a = 7 def get_dynval(module): return "property function returns %s in module %r" % (a * 4, module.__name__) __modclass__.dynval = property(get_dynval) 

Uso:

 >>> import propertymodule PropertyModule stub execution propertymodule regular module execution >>> propertymodule.dynval "property function returns 28 in module 'propertymodule'" >>> reload(propertymodule) # AFTER EDITS regular module execution  >>> propertymodule.dynval "property function returns 36 in module 'propertymodule'" 

Nota: Algo parecido from propertymodule import dynval producirá una copia congelada, por supuesto, correspondiente a dynval = someobject.dynval