Decirle a __import__ dónde buscar, ¿estoy atascado con sys.path?

Tengo un proyecto en Python puro con un sistema de complementos rudimentario: usted escribe un módulo que define una clase con una interfaz y un nombre específicos, y el programa importa el módulo y posteriormente crea una instancia de la clase según sea necesario.

Actualmente, todos los complementos provienen de una carpeta específica (subdirectorio donde se encuentra el archivo .py principal). Me gustaría poder tenerlos en otro lugar del disco e indicarle al programa que busque complementos en un lugar específico. ¿Puedo hacer esto, para importaciones dinámicas únicas, de una manera más limpia que modificando sys.path? No quiero contaminar este global.

Relacionado: puedo contar con sys.path[0] siendo la ruta al script, incluso si difiere del directorio de trabajo actual (os.getcwd())?

EDITAR: Olvidé mencionar: quiero poder obtener complementos de varias carpetas diferentes, con el usuario especificando rutas a las carpetas de complementos. Actualmente, cada una de estas carpetas está configurada como un paquete (con un __init__.py); Puedo desechar esto trivialmente si causa un problema.

preguntado el 28 de agosto de 11 a las 02:08

Para la ruta al script actual, puede usar __file__ -

O, si lo que quiere decir es, ¿puede confiar en que siempre podrá importar módulos en el mismo directorio que el script? Me he encontrado con casos en los que esto falló y desearía poder decir exactamente por qué, pero estaba haciendo algo extraño. cosas. -

Usar __file__ porque esa parte parece más limpia, gracias. Proporciona una ruta relativa que incluye el nombre del archivo en sí, pero que se puede masajear fácilmente con os.path funcionalidad. -

Creo que tu pregunta fue respondida aquí -

@rodrigomanhaes Pensé en eso un poco más tarde, pero preferiría, si es posible, no tener que volver a implementar la lógica de "buscar un .pyc; en caso contrario, buscar un .py". -

1 Respuestas

Esto puede parecer extraño, pero puede modificar la configuración de un módulo. __path__ variable y luego importar desde ella. Entonces no estás jugando con el espacio de importación global en sys.path.

Editar: si los directorios se cargan en tiempo de ejecución, entonces no necesita un archivo plugins.py para almacenarlos. Puede crear el módulo dinámicamente:

main.py:

#create the plugins module (pseudo-package)

import sys, os

sys.modules['plugins'] = plugins = type(sys)('plugins')

plugins.__path__ = []
for plugin_dir in ['plugins1', 'plugins2']:
    path = os.path.join(sys.path[0], 'addons', plugin_dir)
    plugins.__path__.append(path)

Después de crear el módulo dinámico, puede cargar los complementos como antes, usando import_module or __import__:

from importlib import import_module

myplugins = []
for plugin in ['myplugin1', 'myplugin2']:
    myplugins.append(import_module('plugins.' + plugin))
    myplugins[-1].init()

##or using __import__:

myplugins = []
for plugin in ['myplugin1', 'myplugin2']:
    myplugins.append(getattr(__import__('plugins.' + plugin), plugin))
    myplugins[-1].init()

complementos / plugins1 / myplugin1.py:

def init():
    print('myplugin1')

complementos / plugins2 / myplugin2.py:

def init():
    print('myplugin2')

Nunca he usado esto, pero funciona tanto en Python 2 como en 3.

Respondido 28 ago 11, 11:08

Puede que no haya sido claro: quiero poder especificar varias rutas y que cada una de ellas se busque cuando busque un complemento. - Karl Knechtel

Creo que también tendré que experimentar con esto. - Karl Knechtel

importlib parece ser específico de 3.x. - Karl Knechtel

Bien, ahora veo cómo funciona esto y no parece satisfacer mis necesidades. Necesito poder establecer la lista de ubicaciones de importación en tiempo de ejecución y modificar __path__ para un módulo ya importado en tiempo de ejecución no parece funcionar. - Karl Knechtel

Muchas gracias, y lamento darte una vuelta> _ <Mis pruebas en el REPL con la modificación __path__ en un módulo en blanco no funcionó (no he podido averiguar por qué exactamente), pero funciona en un script con el __path__ de un __init__.py. Crear el módulo dinámicamente es un buen truco pero no lo necesito; hay un directorio "base" de complementos que puedo tratar como un paquete y modificar su __path__ en tiempo de ejecución para hacer referencia a carpetas de complementos adicionales. - Karl Knechtel

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.