Una risposta breve: usa proxy_tools
Il proxy_tools
pacchetto tenta di fornire @module_property
funzionalità.
Si installa con
pip install proxy_tools
Usando una leggera modifica dell'esempio di @ Marein, the_module.py
abbiamo inserito
from proxy_tools import module_property
@module_property
def thing():
print(". ", end='') # Prints ". " on each invocation
return 'hello'
Ora da un altro script, posso farlo
import the_module
print(the_module.thing)
# . hello
Comportamento inaspettato
Questa soluzione non è priva di avvertimenti. Vale a dire, nonthe_module.thing
è una stringa ! È un proxy_tools.Proxy
oggetto i cui metodi speciali sono stati sovrascritti in modo che imiti una stringa. Ecco alcuni test di base che illustrano il 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 funzione originale viene memorizzata in the_module.thing._Proxy__local
:
print(res._Proxy__local)
# <function thing at 0x7f729c3bf680>
Ulteriori pensieri
Onestamente, sono sconcertato dal motivo per cui i moduli non hanno questa funzionalità incorporata. Penso che il nocciolo della questione sia che the_module
è un'istanza della types.ModuleType
classe. L'impostazione di una "proprietà del modulo" equivale a impostare una proprietà su un'istanza di questa classe, piuttosto che sulla types.ModuleType
classe stessa. Per maggiori dettagli, vedi questa risposta .
Possiamo effettivamente implementare le proprietà types.ModuleType
come segue, sebbene i risultati non siano eccezionali. Non possiamo modificare direttamente i tipi incorporati, ma possiamo maledirli :
# 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__}'))
Questo ci dà una proprietà che esiste su tutti i moduli. È un po 'ingombrante, poiché interrompiamo il comportamento delle impostazioni in tutti i moduli:
import sys
print(sys.thing2)
# hi from sys
sys.thing2 = 5
# AttributeError: can't set attribute
__getattr__
su un modulo per una soluzione più moderna.