Короткий ответ: используйте proxy_tools
proxy_tools
Пакет пытается обеспечить @module_property
функциональные возможности .
Он устанавливается с
pip install proxy_tools
Используя небольшую модификацию примера @Marein, the_module.py
мы помещаем
from proxy_tools import module_property
@module_property
def thing():
print(". ", end='') # Prints ". " on each invocation
return 'hello'
Теперь из другого сценария я могу сделать
import the_module
print(the_module.thing)
# . hello
Неожиданное поведение
Это решение не лишено недостатков. А именно the_module.thing
это не строка ! Это proxy_tools.Proxy
объект, специальные методы которого были переопределены, чтобы имитировать строку. Вот несколько основных тестов, которые иллюстрируют это:
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']
Внутри исходная функция сохраняется в the_module.thing._Proxy__local
:
print(res._Proxy__local)
# <function thing at 0x7f729c3bf680>
Дальнейшие мысли
Честно говоря, я сбит с толку, почему в модули не встроена эта функциональность. Я думаю, что суть вопроса в том, что the_module
это экземпляр types.ModuleType
класса. Установка «свойства модуля» сводится к установке свойства на экземпляре этого класса, а не на самом types.ModuleType
классе. Подробнее см. В этом ответе .
Фактически мы можем реализовать свойства types.ModuleType
следующим образом, хотя результаты невелики. Мы не можем напрямую изменять встроенные типы, но можем проклинать их:
# 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__}'))
Это дает нам свойство, которое существует для всех модулей. Это немного громоздко, так как мы нарушаем поведение настроек для всех модулей:
import sys
print(sys.thing2)
# hi from sys
sys.thing2 = 5
# AttributeError: can't set attribute
__getattr__
Модуль для более современного решения.