Вызываемые модули
Почему Python не позволяет модулям иметь __call__
? (Помимо очевидного, что его было бы непросто импортировать напрямую.) В частности, почему синтаксис a(b)
не использует атрибут __call__
, как это делает для функций, классов и объектов? (Является ли поиск просто несовместимым для модулей?)
>>> print open("mod_call.py").read()
def __call__():
return 42
>>> import mod_call
>>> mod_call()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'module' object is not callable
>>> mod_call.__call__()
42
Ответы
Ответ 1
Специальные методы гарантируют, что они будут неявно называться неявно, если они определены в типе, а не в экземпляре. (__call__
- это атрибут экземпляра модуля mod_call
, а не <type 'module'>
.) Вы не можете добавлять методы к встроенным типам.
http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes
Ответ 2
Python не позволяет модулю переопределять или добавлять какой-либо магический метод, потому что сохранение объектов модуля простым, регулярным и легким просто слишком выгодно, учитывая, как редко появляются сильные примеры использования, где вы можете использовать магические методы.
Когда такие примеры использования появляются, решение состоит в том, чтобы сделать экземпляр класса masquerade как модуль. В частности, введите код mod_call.py
следующим образом:
import sys
class mod_call(object):
def __call__(self):
return 42
sys.modules[__name__] = mod_call()
Теперь ваш код импорта и вызова mod_call
работает нормально.
Ответ 3
Как говорит Майлз, вам нужно определить вызов на уровне класса. Поэтому альтернативой сообщению Alex является изменение класса sys.modules[__name__]
на подкласс типа sys.modules[__name__]
(это должны быть types.ModuleType
).
Это имеет то преимущество, что модуль можно вызывать, сохраняя все остальные свойства модуля (например, доступ к функциям, переменным,...).
import sys
class MyModule(sys.modules[__name__].__class__):
def __call__(self): # module callable
return 42
sys.modules[__name__].__class__ = MyModule
Примечание. Протестировано с помощью python3.6.