Importar el paquete de Python desde el directorio local al intérprete

86

Estoy desarrollando / probando un paquete en mi directorio local. Quiero importarlo en el intérprete (v2.5), pero sys.path no incluye el directorio actual. Ahora mismo escribo sys.path.insert(0,'.'). ¿Existe una forma mejor?

También,

from . import mypackage

falla con este error:

ValueError: Attempted relative import in non-package
proyectos
fuente
Dónde leíste eso "." era un módulo de Python?
S.Lott
16
@Lott: Es una ruta de importación relativa que se describe aquí: docs.python.org/reference/…
projectshave
1
Es posible que desee ver esta guía definitiva chrisyeh96.github.io/2017/08/08/…
Kevin Zhu

Respuestas:

44

Puede usar importaciones relativas solo desde un módulo que a su vez fue importado como parte de un paquete; su script o intérprete interactivo no lo fue, así que, por supuesto from . import(lo que significa "importar desde el mismo paquete del que lo importé") no no funciona. import mypackageva a estar bien una vez que se asegura el directorio padre de mypackageestá en sys.path(cómo le hizo para obtener su directorio actual de distancia de sys.pathno sé - ¿tienes algo extraño en site.py, o ...)

De hecho, para recuperar su directorio actual sys.pathno hay mejor manera que ponerlo allí.

Alex Martelli
fuente
Python 2.5 para Ubuntu 8.10 no tiene el directorio actual (cadena vacía) en sys.path para el intérprete. No cambié nada, por lo que de alguna manera se envió de esa manera. Acabo de instalar 3.0 y sys.path TIENE '' en sys.path.
proyectos tienen
@projectshave, OK, ¡Ubuntu sin duda tiene sus razones! No me he dado cuenta de eso en 8.04 (lo que usamos actualmente en el trabajo) pero tal vez no estaba prestando suficiente atención.
Alex Martelli
1
Estoy parcialmente equivocado. Python invocado desde un shell tiene el directorio actual en sys.path. Python invocado desde Emacs no tiene el directorio actual. Extraño.
proyectos tienen
1
Ah, bueno, entonces es Emacs quien tiene sus razones en contraposición a las de Ubuntu (como usuario de vim realmente no lo sé ;-). Puede insertar condicionalmente '.' en su sys.path si no está allí, por supuesto.
Alex Martelli
@Alex Martelli: ¡Muchas gracias! He estado buscando y buscando la solución de por qué mi complemento (para Anki) necesitaba una declaración de importación diferente cuando se ejecutaba 'localmente' como un script. Cuando en cambio agregué un método local_launch () e importé / lancé todo desde un script fuera de la carpeta del paquete, ¡funcionó como un encanto!
Jon Coombs
17

Consulte la documentación de sys.path:

http://docs.python.org/library/sys.html#sys.path

Citar:

Si el directorio del script no está disponible (por ejemplo, si el intérprete se invoca de forma interactiva o si el script se lee desde la entrada estándar), la ruta [0] es la cadena vacía, que indica a Python que busque primero los módulos en el directorio actual.

Por lo tanto, no es necesario manipular sys.path si está iniciando el intérprete de Python desde el directorio que contiene su módulo.

Además, para importar su paquete, simplemente haga:

import mypackage

Dado que el directorio que contiene el paquete ya está en sys.path, debería funcionar bien.

SpoonMeiser
fuente
1
Fallará si existe un nombre de archivo similar en algún otro lugar del entorno de trabajo.
JAR.JAR.beans
@ JAR.JAR.beans el directorio de trabajo actual debe ser lo primero en sys.pathlo que los archivos deben encontrarse antes que los archivos en cualquier otro lugar del entorno de trabajo.
SpoonMeiser
3
Buen punto. Es decir, si ejecutamos el archivo desde el directorio local. En el caso de que sea otra carpeta, y en el caso de que se necesite un cambio a sys.path, significa en sys.path.insert(0, new_path)lugar de sys.path.append(new_path).
JAR.JAR.beans
14

Si desea ejecutar un script de Python sin modificar para que importe bibliotecas de un directorio local específico, puede configurar la PYTHONPATHvariable de entorno, por ejemplo, en bash:

export PYTHONPATH=/home/user/my_libs
python myscript.py

Si solo desea que se importe desde el directorio de trabajo actual, use la .notación:

export PYTHONPATH=.
python myscript.py
Pierz
fuente
Exportar PYTHONPATH incluye programación fuera de Python (por ejemplo, en bash). Además, en docs.python.org/3/using/cmdline.html se indica claramente que "la ruta de búsqueda predeterminada depende de la instalación ".
ilias iliadis
13

Mantenlo simple:

 try:
     from . import mymodule     # "myapp" case
 except:
     import mymodule            # "__main__" case
Guido U. Draheim
fuente
7
Me gusta esta solución, es la más sencilla. La única pregunta que queda es por qué la regla de "una única forma de hacerlo" se ha considerado opcional al implementar las importaciones ... En serio, hay alrededor de 15 formas de declarar y organizar los paquetes, todas las cuales tienen inconvenientes
Léo Germond
5

Una manera simple de hacer que el trabajo es ejecutar la secuencia de comandos desde el directorio padre usando pitón de -mbandera, por ejemplo python -m packagename.scriptname. Obviamente, en esta situación, necesita un __init__.pyarchivo para convertir su directorio en un paquete.

bradley.ayers
fuente
5

Dentro de un paquete si hay setup.py , es mejor instalarlo

pip install -e .
Nagashayan
fuente
3

El uso ya sys.pathdebería incluir el directorio actual.

Tratar:

import .

o:

from . import sth

sin embargo, puede que no sea una buena práctica, así que ¿por qué no usar simplemente:

import mypackage
sunqiang
fuente
5
El problema con <import mypackage> es que cargará el paquete desde el entorno python global, podría cargar el paquete / archivo desde la carpeta local, pero también podría cargar algún otro mypackge aleatorio que esté en el entorno de trabajo.
JAR.JAR.beans
2

Un poco tarde para la fiesta, pero esto es lo que funcionó para mí:

>>> import sys
>>> sys.path.insert(0, '')

Aparentemente, si hay una cadena vacía, Python sabe que debería buscar en el directorio actual. No tenía la cadena vacía sys.path, lo que causó este error.

hombre en la computadora
fuente
0

Solía pathlibagregar el directorio de mi módulo a la ruta de mi sistema porque quería evitar instalar el módulo como un paquete y la respuesta de @maninthecomputer no me funcionó

import sys
from pathlib import Path

cwd = str(Path(__file__).parent)
sys.path.insert(0, cwd)
from my_module import my_function
rdmolony
fuente