Estoy tratando de omitir la importación desde un módulo, así que en mi __init__.py puedo inyectar código como este:

globals().update(
    {
         "foo": lambda: print("Hello stackoverflow!")
    }
)

Así que si lo hago import mymodule podré llamar a mymodule.foo. Ese es un concepto simple, inútil para el propósito porque en realidad solo puedes definir foo. Entonces, la idea es modificar el diccionario del módulo globals, por lo que en caso de que no encuentre la función foo irá a donde sea y puedo inyectar el código, para eso intenté:

from importer import load #a load function to search for the code
from functools import wraps

def global_get_wrapper(f):
    @wraps(f)
    def wrapper(*args):
        module_name, default = args
        res = f(*args)
        if res is None:
            return load(module_name)
        return res
    return wrapper

globals().get = global_get_wrapper(globals().get) # trying to substitute get method

Pero me da un error:

AttributeError: 'dict' object attribute 'get' is read-only

La otra idea que tuve es precargar los nombres de funciones, clases, etc. disponibles en el diccionario del módulo y cargarlos perezosamente más tarde.

Me quedo sin ideas para lograr esto y no sé si esto es posible. ¿Debo ir a escribir mi propio importador de python? ¿O hay alguna otra posibilidad en la que no podría pensar? Gracias por adelantado.

3
Netwave 3 mar. 2018 a las 15:32

3 respuestas

La mejor respuesta

En lugar de piratear globals(), sería mejor definir __getattr__ para su módulo de la siguiente manera:

Module_name.py

foo = 'foo'

def bar():
    return 'bar'

My_module.py

import sys

import module_name

class MyModule(object):
    def foobar(self):
        return 'foobar'

    def __getattr__(self, item):
        return getattr(module_name, item)

sys.modules[__name__] = MyModule()

Y entonces:

>>> import my_module
>>> my_module.foo
'foo'
>>> my_module.bar()
'bar'
>>> my_module.foobar()
'foobar'
9
Vader 6 mar. 2018 a las 22:02

No entiendo del todo. Que este trabajo para usted?

try:
    mymodule.foo()
except:
    print("whatever you wanted to do")
0
Artemis still doesn't trust SE 6 mar. 2018 a las 16:21

PEP 562, que se dirige a Python 3.7, presenta __getattr__ para módulos En la lógica también describe soluciones alternativas para versiones anteriores de Python.

A veces es conveniente personalizar o tener control sobre el acceso a los atributos del módulo. Un ejemplo típico es la gestión de advertencias de desuso. Las soluciones típicas son asignar __class__ de un objeto de módulo a una subclase personalizada de types.ModuleType o reemplazar el elemento sys.modules con una instancia de contenedor personalizada. Sería conveniente simplificar este procedimiento al reconocer __getattr__ definido directamente en un módulo que actuaría como un método normal __getattr__, excepto que se definirá en las instancias del módulo.

Entonces su mymodule puede verse así:

foo = 'bar'

def __getattr__(name):
    print('load you custom module and return it')

Así es como se comporta:

>>> import mymodule
>>> mymodule.foo
'bar'
>>> mymodule.baz
load you custom module and return it
3
saaj 8 mar. 2018 a las 09:31