Une réponse courte: utiliser proxy_tools
Le proxy_tools
package tente de fournir@module_property
fonctionnalités.
Il s'installe avec
pip install proxy_tools
En utilisant une légère modification de l'exemple de @ Marein, the_module.py
nous mettons
from proxy_tools import module_property
@module_property
def thing():
print(". ", end='') # Prints ". " on each invocation
return 'hello'
Maintenant à partir d'un autre script, je peux faire
import the_module
print(the_module.thing)
# . hello
Comportement inattendu
Cette solution n'est pas sans réserves. A savoir, the_module.thing
n'est pas une chaîne ! C'est un proxy_tools.Proxy
objet dont les méthodes spéciales ont été surchargées pour imiter une chaîne. Voici quelques tests de base qui illustrent ce point:
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']
En interne, la fonction d'origine est stockée dans the_module.thing._Proxy__local
:
print(res._Proxy__local)
# <function thing at 0x7f729c3bf680>
Réflexions supplémentaires
Honnêtement, je ne sais pas pourquoi les modules n'ont pas cette fonctionnalité intégrée. Je pense que le nœud du problème est qu'il the_module
s'agit d'une instance de la types.ModuleType
classe. Définir une "propriété de module" revient à définir une propriété sur une instance de cette classe, plutôt que sur la types.ModuleType
classe elle-même. Pour plus de détails, consultez cette réponse .
Nous pouvons réellement implémenter des propriétés types.ModuleType
comme suit, bien que les résultats ne soient pas excellents. Nous ne pouvons pas modifier directement les types intégrés, mais nous pouvons les maudire :
# 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__}'))
Cela nous donne une propriété qui existe sur tous les modules. C'est un peu difficile à manier, car nous cassons le comportement des paramètres dans tous les modules:
import sys
print(sys.thing2)
# hi from sys
sys.thing2 = 5
# AttributeError: can't set attribute
__getattr__
sur un module pour une solution plus moderne.