¿Cómo puedo importar un módulo dinámicamente dada la ruta completa?

8 minutos de lectura

avatar de usuario de derfred
derfred

¿Cómo cargo un módulo de Python dada su ruta completa?

Tenga en cuenta que el archivo puede estar en cualquier parte del sistema de archivos donde el usuario tenga derechos de acceso.


Ver también: ¿Cómo importar un módulo dado su nombre como cadena?

  • Pregunta agradable y simple, y respuestas útiles, pero me hacen preguntarme qué sucedió con el mantra de Python “Hay una obvio “manera” de hacerlo… No parece una respuesta única o simple y obvia… Parece ridículamente hacky y depende de la versión para una operación tan fundamental (y se ve más inflada en las versiones más nuevas. .).

    – dedo

    6 de diciembre de 2019 a las 12:08

  • @inger lo que sucedió con el mantra de python “Hay una forma obvia” de hacerlo […] [not] una sola o una respuesta simple y obvia a la misma […] ridículamente hacky[…] más hinchado en versiones más nuevas Bienvenido al terrible mundo de la gestión de paquetes de Python. de pitón import, virtualenv, pip, setuptools todo lo demás debe desecharse y reemplazarse con un código de trabajo. Solo traté de asimilar virtualenv o era pipenv y tuvo que trabajar a través del equivalente de un manual de Jumbo Jet. Cómo se presenta ese artilugio como La solución para lidiar con los deps se me escapa por completo.

    – John Fraser

    26 de junio de 2020 a las 20:59


  • XKCD relevante xkcd.com/1987

    – John Fraser

    26 de junio de 2020 a las 21:08

  • @JohnFrazer ha empeorado por las constantes molestias de las personas que no se molestaron en leer 2 párrafos de documentación. Su XKCD no es realmente relevante, ya que muestra lo que este tipo de personas pueden lograr cuando intentan cosas hasta que algo funciona. Además, el hecho de que haya una nueva forma no significa que ahora haya “dos formas obvias”. La forma antigua es obvia para algunos casos, la nueva forma presenta facilidad de uso para otros. Eso es lo que sucede cuando realmente te preocupas por DevX.

    – Blazej Michalik

    2 de diciembre de 2020 a las 0:13


  • Y piense que Java o incluso PHP (en estos días) tienen una forma clara y simple de dividir las cosas en paquetes/espacios de nombres y reutilizarlos. Es impactante ver tanto dolor en Python, que adoptó la simplicidad en todos los demás aspectos.

    – Alex

    27 de enero de 2021 a las 7:46

La ventaja de agregar una ruta a sys.path (en lugar de usar imp) es que simplifica las cosas al importar más de un módulo de un solo paquete. Por ejemplo:

import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')

from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch

  • ¿Cómo usamos sys.path.append para apuntar a un solo archivo de python en lugar de un directorio?

    – Fani

    13 de enero de 2014 a las 17:46

  • 🙂 Quizás su pregunta sería más adecuada como una pregunta de StackOverflow, no como un comentario sobre una respuesta.

    – Daryl Spitzer

    6 de marzo de 2015 a las 0:12

  • La ruta de python puede contener archivos zip, “eggs” (un tipo complejo de archivos zip), etc. Los módulos se pueden importar de ellos. Así que los elementos de la ruta son de hecho contenedores de archivos, pero no necesariamente son directorios.

    – alexis

    30/04/2015 a las 21:21

  • Tenga cuidado con el hecho de que Python almacena en caché las declaraciones de importación. En el raro caso de que tenga dos carpetas diferentes que compartan un solo nombre de clase (classX), el enfoque de agregar una ruta a sys.path, importar classX, eliminar la ruta y repetir para las rutas restantes no funcionará. Python siempre cargará la clase desde la primera ruta desde su caché. En mi caso, mi objetivo era crear un sistema de complementos donde todos los complementos implementaran una clase X específica. Terminé usando SourceFileLoader, tenga en cuenta que es la desaprobación es controvertida.

    – ComFreek

    3 de julio de 2015 a las 17:18


  • Tenga en cuenta que este enfoque permite que el módulo importado importe otros módulos desde el mismo directorio, lo que los módulos suelen hacer, mientras que el enfoque de la respuesta aceptada no lo hace (al menos en 3.7). importlib.import_module(mod_name) se puede usar en lugar de la importación explícita aquí si el nombre del módulo no se conoce en tiempo de ejecución, agregaría un sys.path.pop() al final, sin embargo, suponiendo que el código importado no intente importar más módulos a medida que se usa.

    – Eli_B

    6 mayo 2019 a las 21:45

  • Esta solución “temporal” es una excelente respuesta si desea impulsar un proyecto en un cuaderno jupyter en otro lugar.

    – Ford

    16 de noviembre de 2018 a las 17:20

  • Pero… es peligroso manipular el camino.

    – Shai Alon

    10 de noviembre de 2019 a las 15:56

  • @ShaiAlon Está agregando rutas, por lo que no hay más peligro que cuando transfiere códigos de una computadora a otra, las rutas pueden estropearse. Entonces, para el desarrollo de paquetes, solo importo paquetes locales. Además, los nombres de los paquetes deben ser únicos. Si está preocupado, use la solución temporal.

    – Miladiosas

    13 de noviembre de 2019 a las 0:11


  • Tuve dificultades para importar mis pruebas unitarias, y su temperatura funcionó bien. Lo modifiqué para importar desde el mismo directorio que Unit Test con: >>> import os >>> import sys >>> sys.path.append(os.getcwd())

    – brewmanz

    19 de septiembre a las 3:45


Avatar de usuario de Sam Grondahl
Sam Grondahl

Si su módulo de nivel superior no es un archivo sino que está empaquetado como un directorio con __init__.py, entonces la solución aceptada casi funciona, pero no del todo. En Python 3.5+ se necesita el siguiente código (tenga en cuenta la línea agregada que comienza con ‘sys.modules’):

MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module 
spec.loader.exec_module(module)

Sin esta línea, cuando se ejecuta exec_module, intenta vincular las importaciones relativas en su nivel superior __init__.py al nombre del módulo de nivel superior, en este caso, “mymodule”. Pero “mymodule” aún no está cargado, por lo que obtendrá el error “SystemError: el módulo principal ‘mymodule’ no está cargado, no puede realizar una importación relativa”. Por lo tanto, debe vincular el nombre antes de cargarlo. La razón de esto es la invariante fundamental del sistema de importación relativo: “La propiedad invariante es que si tiene sys.modules[‘spam’] y sys.módulos[‘spam.foo’] (como lo haría después de la importación anterior), el último debe aparecer como el atributo foo del primero” como se discute aquí.

  • ¡Muchas gracias! Este método permite importaciones relativas entre submódulos. ¡Excelente!

    – tebanep

    10 oct 2019 a las 14:09

  • Esta respuesta coincide con la documentación aquí: docs.python.org/3/library/….

    -Tim Ludwinski

    9 de diciembre de 2019 a las 16:08

  • pero que es mymodule?

    – Gulzar

    20 de enero de 2020 a las 10:02

  • @Gulzar, es el nombre que le gustaría darle a su módulo, de modo que luego pueda hacer: “from mymodule import myclass”

    – Idodo

    16 de febrero de 2020 a las 22:44

  • Aunque no es convencional, si el punto de entrada de su paquete es diferente a __init__.py, aún puede importarlo como un paquete. Incluir spec.submodule_search_locations = [os.path.dirname(MODULE_PATH)] después de crear la especificación. También puede tratar un __init__.py como un no paquete (por ejemplo, módulo único) estableciendo este valor en None

    – Azmísov

    5 de noviembre de 2020 a las 20:32

Avatar de usuario de Peter Mortensen
Pedro Mortensen

Parece que no desea importar específicamente el archivo de configuración (que tiene muchos efectos secundarios y complicaciones adicionales). Solo desea ejecutarlo y poder acceder al espacio de nombres resultante. La biblioteca estándar proporciona una API específicamente para eso en forma de runpy.run_path:

from runpy import run_path
settings = run_path("/path/to/file.py")

Esa interfaz está disponible en Python 2.7 y Python 3.2+.

  • ¡Muchas gracias! Este método permite importaciones relativas entre submódulos. ¡Excelente!

    – tebanep

    10 oct 2019 a las 14:09

  • Esta respuesta coincide con la documentación aquí: docs.python.org/3/library/….

    -Tim Ludwinski

    9 de diciembre de 2019 a las 16:08

  • pero que es mymodule?

    – Gulzar

    20 de enero de 2020 a las 10:02

  • @Gulzar, es el nombre que le gustaría darle a su módulo, de modo que luego pueda hacer: “from mymodule import myclass”

    – Idodo

    16 de febrero de 2020 a las 22:44

  • Aunque no es convencional, si el punto de entrada de su paquete es diferente a __init__.py, aún puede importarlo como un paquete. Incluir spec.submodule_search_locations = [os.path.dirname(MODULE_PATH)] después de crear la especificación. También puede tratar un __init__.py como un no paquete (por ejemplo, módulo único) estableciendo este valor en None

    – Azmísov

    5 de noviembre de 2020 a las 20:32

Avatar de usuario de Peter Mortensen
Pedro Mortensen

También puede hacer algo como esto y agregar el directorio en el que se encuentra el archivo de configuración a la ruta de carga de Python, y luego simplemente hacer una importación normal, suponiendo que conoce el nombre del archivo de antemano, en este caso “config”.

Desordenado, pero funciona.

configfile="~/config.py"

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config

  • Eso no es dinámicamente.

    – Shai Alon

    10 de noviembre de 2019 a las 16:10

  • Probé: config_file = ‘setup-for-chats’, setup_file = get_setup_file(config_file + “.py”), sys.path.append(os.path.dirname(os.path.expanduser(setup_file))), import config_file >> “ImportError: ningún módulo llamado config_file”

    – Shai Alon

    10 de noviembre de 2019 a las 16:17


¿Ha sido útil esta solución?