Importar desde una ruta relativa en Python

Respuestas:

140

EDITAR noviembre de 2014 (3 años después):

Python 2.6 y 3.x soporta importaciones relativas adecuadas, donde puede evitar hacer algo hack. Con este método, sabe que está obteniendo una importación relativa en lugar de una importación absoluta . El '..' significa, vaya al directorio encima de mí:

from ..Common import Common

Como advertencia, esto solo funcionará si ejecuta su python como un módulo, desde fuera del paquete. Por ejemplo:

python -m Proj

Manera hacky original

Este método todavía se usa comúnmente en algunas situaciones, donde en realidad nunca está 'instalando' su paquete. Por ejemplo, es popular entre los usuarios de Django.

Puede agregar Common / a su sys.path (la lista de rutas que Python mira para importar cosas):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) simplemente le da el directorio en el que se encuentra su archivo Python actual, y luego navegamos a 'Común /' el directorio e importamos 'Común' el módulo.

Dave
fuente
2
No modifique la ruta de los módulos de Python manualmente, puede ser solo para hacks rápidos. Aprender la administración de paquetes de Python usando distutils, setuptools, etc., suele ser una habilidad necesaria que resolverá problemas como ese.
Sascha Gottfried
1
@SaschaGottfried está totalmente de acuerdo, aunque si no está creando un paquete distribuible, probablemente no importe. Por ejemplo, en Django nunca instalas realmente tu aplicación con distutils, por lo que el método anterior es un truco fácil. Pero de todos modos he editado la respuesta con lo que haría estos días.
Dave
32
Gracias por responder la pregunta real en lugar de predicar sobre la técnica adecuada. Hay muchas buenas razones para realizar importaciones relativas.
musaraña
¿Cómo subirías más de un nivel?
jxramos
10
para subir un nivel más, use un punto adicional para cada nivel. @jxramos ex: from ...myfileva a../../myfile
WattsInABox
10

Es bastante gracioso, el mismo problema que acabo de conocer, y obtengo este trabajo de la siguiente manera:

Combinando con el comando Linux ln, podemos hacer que las cosas sean mucho más sencillas:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

Y, ahora, si desea importar some_stuffdesde el archivo: Proj/Common/Common.pya su archivo:, Proj/Client/Client.pyasí:

# in Proj/Client/Client.py
from Common.Common import some_stuff

Y lo mismo se aplica a Proj/Server, también funciona para el setup.pyproceso, una misma pregunta discutida aquí , ¡espero que ayude!

jacoolee
fuente
10

No hagas una importación relativa.

Desde PEP8 :

Se desaconsejan en gran medida las importaciones relativas para las importaciones dentro del paquete.

Pon todo tu código en un súper paquete (es decir, "myapp") y usa subpaquetes para cliente, servidor y código común.

Actualización: " Python 2.6 y 3.x admite importaciones relativas adecuadas (...) ". Vea las respuestas de Dave para más detalles.

Michał Šrajer
fuente
1
Imagine que agrega un código al final del cliente y el servidor después de la if __name__ == "__main__":línea " ". Es decir, desea poder utilizarlos como scripts independientes. ¿Cómo hacerlo correctamente? Creo que es un caso de uso perfectamente común que debería ser compatible. ¿Por qué está desanimado?
Jabba
83
Estoy sorprendido de que "no lo hagas", es la respuesta aceptada para un "¿Cómo ...?" Pregunta (bueno, excepto por los carriles <> g.) No hay razones para hacer esto de vez en cuando. Utilizo una solución similar a la que sugiere Dave.
Tom Wilson
1
@TomWilson: No es pura respuesta de "no lo hagas". Hay "hazlo de esta manera" a continuación.
Michał Šrajer
2
¡Alguien debería decírselo a los chicos de Numpy! ¡Usan una TONELADA de importaciones relativas!
Austin A
12
Esta respuesta no es aplicable a las versiones actuales de Python. La parte citada ya no se encuentra en PEP 8. Hoy en día se lee así: "Las importaciones relativas explícitas son una alternativa aceptable a las importaciones absolutas, especialmente cuando se trata de diseños de paquetes complejos donde el uso de importaciones absolutas sería innecesariamente detallado"
moooeeeep
8

¡Hacer una importación relativa está absolutamente bien! Esto es lo que hace mi pequeño:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py
Gary Beardsley
fuente
1
Pero es mejor que sepa hacia dónde apunta sys.argv [0]: no es (probablemente) el directorio en el que se encontraba cuando inició Python.
CarlH
Este es un truco rápido, con muchas trampas. Pero la pregunta no era mejor.
Sascha Gottfried
1
Esto está claramente escrito, pero el truco original en la respuesta de Dave es mejor porque se usa __file__para obtener la relación adecuada del archivo actual
John Neuhaus
4

El método de importación predeterminado ya es "relativo", de PYTHONPATH. El PYTHONPATH es por defecto para algunas bibliotecas del sistema junto con la carpeta del archivo fuente original. Si ejecuta con -m para ejecutar un módulo, el directorio actual se agrega a PYTHONPATH. Entonces, si el punto de entrada de su programa está dentro de Proj, entonces el uso import Common.Commondebería funcionar dentro de Server.py y Client.py.

No hagas una importación relativa. No funcionará como usted quiere.

Jonathan Sternberg
fuente
1
Si esto es cierto, ¿por qué las respuestas principales no dicen esto? ¿Funcionará esto o no?
Anónimo