2009-06-29 16 views
41

¿Por qué Python no permite que los módulos tengan un __call__? (Más allá de lo obvio de que no sería fácil importar directamente.) Específicamente, ¿por qué el uso de la sintaxis a(b) no encuentra el atributo __call__ como lo hace para funciones, clases y objetos? (Es de búsqueda acaba de manera incompatible diferente para módulos?)Módulos que se pueden llamar

>>> 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 
+0

Migración de un decorador desde un paquete a su propio submódulo. @example (...) era, con mucho, el caso de uso más común, pero @ example.special_case (...) era un nuevo uso. No quería implementarlo con una clase de ejemplo y métodos estáticos, ya que era un mal ajuste. No estoy seguro de que un módulo llamable sea más adecuado, pero comencé a investigarlo y luego quise saber por qué no funcionó. –

+3

También pensé que podría simplificar algunos módulos como datetime y decimal, haciendo que el módulo .__ call__ sea datetime.datetime o decimal.Decimal respectivamente. Sin embargo, entonces el tipo (decimal ('1')) no sería lo mismo que el decimal, y otros posibles problemas. * encogerse de hombros * Fue una idea. –

+0

"Más allá de lo obvio que no sería fácil importar directamente". ¿Por qué piensas eso? –

Respuesta

29

métodos especiales sólo se garantizan para ser llamado de forma implícita cuando se definen el tipo, no en la instancia. (__call__ es un atributo de la instancia del módulo mod_call, no de <type 'module'>). No puede agregar métodos a los tipos incorporados.

http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes

+0

¡Parece la respuesta correcta para mí! Desde la perspectiva de vista de pájaro, parece un defecto de diseño en Python. ¿Otro diseño sería intrínsecamente difícil o incluso imposible? – jolvi

75

Python no permite módulos para anular o añadir cualquier método mágico, ya que para mantener módulo de objetos simples, regulares y ligero es demasiado ventajosa teniendo en cuenta la fuerte raramente casos de uso aparecen donde se podía usar la magia métodos allí.

Cuando aparecen tales casos de uso do, la solución es hacer que una instancia de clase se enmascare como un módulo. En concreto, el código de su mod_call.py de la siguiente manera:

import sys 
class mod_call(object): 
    def __call__(self): 
    return 42 
sys.modules[__name__] = mod_call() 

Ahora su código de importación y llamando mod_call funciona bien.

+1

Wow. Estuve a segundos de publicar un ejemplo de código basado en este ejemplo tuyo: http://stackoverflow.com/questions/880530/can-python-modules-have-properties-the-same-way-that-objects-can/880550 # 880550 – Stephan202

+2

Je, SO se siente como una prueba de reflejos a veces! -) –

+0

Gracias por la perspectiva, Alex. – gahooa

2

Como dice Miles, debe definir la llamada en el nivel de clase. Entonces, una alternativa a Alex post es cambiar la clase de sys.modules[__name__] a una subclase del tipo sys.modules[__name__] (debe ser types.ModuleType).

Esto tiene la ventaja de que el módulo es invocable y conserva todas las demás propiedades del módulo (como el acceso a funciones, variables, ...).

import sys 

class MyModule(sys.modules[__name__].__class__): 
    def __call__(self): # module callable 
     return 42 

sys.modules[__name__].__class__ = MyModule 

Nota: Probado con python3.6.

Cuestiones relacionadas