python - from - Importando módulos desde la carpeta padre
python import module from path (16)
Aquí hay una respuesta que es simple para que pueda ver cómo funciona, pequeña y multiplataforma.
Solo usa módulos incorporados ( os
, sys
e inspect
) así que debería funcionar
en cualquier sistema operativo (SO) porque Python está diseñado para eso.
Código más corto para respuesta - menos líneas y variables
from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module # Replace "my_module" here with the module name.
sys.path.pop(0)
Por menos líneas que esta, reemplace la segunda línea con import os.path as path, sys, inspect
,
añadir inspect.
al inicio de getsourcefile
(línea 3) y elimine la primera línea.
- Sin embargo, esto importa todo el módulo, por lo que podría necesitar más tiempo, memoria y recursos.
El código de mi respuesta ( versión más larga ).
from inspect import getsourcefile
import os.path
import sys
current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]
sys.path.insert(0, parent_dir)
import my_module # Replace "my_module" here with the module name.
Utiliza un ejemplo de una respuesta de desbordamiento de pila. ¿Cómo obtengo la ruta de la actual?
archivo ejecutado en Python? para encontrar la fuente (nombre de archivo) del código en ejecución con una herramienta incorporada.
from inspect import getsourcefile from os.path import abspath
A continuación, donde quiera que desee encontrar el archivo de origen, simplemente use:
abspath(getsourcefile(lambda:0))
Mi código agrega una ruta de archivo a sys.path
, la lista de rutas de python
porque esto le permite a Python importar módulos de esa carpeta.
Después de importar un módulo en el código, es una buena idea ejecutar sys.path.pop(0)
en una nueva línea
cuando esa carpeta agregada tiene un módulo con el mismo nombre que otro módulo que se importa
mas tarde en el programa. Debe eliminar el elemento de lista agregado antes de la importación, no otras rutas.
Si su programa no importa otros módulos, es seguro no eliminar la ruta del archivo porque
después de que un programa finaliza (o reinicia el shell de Python), las ediciones realizadas en sys.path
desaparecen.
Notas sobre una variable de nombre de archivo
Mi respuesta no usa la variable __file__
para obtener la ruta de archivo / nombre de archivo de la ejecución
código porque los usuarios aquí a menudo lo han descrito como poco fiable . No deberias usarlo
para importar módulos de la carpeta principal en programas utilizados por otras personas.
Algunos ejemplos en los que no funciona (cita de this pregunta de desbordamiento de pila):
• no se puede encontrar en algunas plataformas • a veces no es la ruta completa del archivo
py2exe
no tiene un atributo__file__
, pero hay una solución alternativa- Cuando se ejecuta desde IDLE con
execute()
no hay ningún atributo__file__
- OS X 10.6 donde obtengo
NameError: global name ''__file__'' is not defined
Estoy ejecutando Python 2.5.
Este es mi árbol de carpetas:
ptdraft/
nib.py
simulations/
life/
life.py
(También tengo __init__.py
en cada carpeta, omitido aquí para __init__.py
lectura)
¿Cómo importo el módulo de nib
desde dentro del módulo de life
? Espero que sea posible hacerlo sin retoques con sys.path.
Nota: El módulo principal que se está ejecutando está en la carpeta ptdraft
.
Aquí hay una solución más genérica que incluye el directorio principal en sys.path (funciona para mí):
import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
Cuando no se encuentra en un entorno de paquete con archivos __init__.py
, la biblioteca pathlib (incluida con> = Python 3.4) hace que sea muy conciso e intuitivo agregar la ruta del directorio principal a PYTHONPATH:
import sys
from pathlib import Path
sys.path.append(str(Path(''.'').absolute().parent))
El mismo tipo de estilo que la respuesta pasada, pero en menos líneas: P
import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)
archivo devuelve la ubicación en la que está trabajando
En un sistema Linux, puede crear un enlace flexible desde la carpeta "life" al archivo nib.py. Entonces, simplemente puedes importarlo como:
import nib
Las importaciones relativas (como en from .. import mymodule
) solo funcionan en un paquete. Para importar ''mymodule'' que se encuentra en el directorio principal de su módulo actual:
import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir)
import mymodule
editar : el atributo __file__
no siempre se da. En lugar de usar os.path.abspath(__file__)
, sugerí usar el módulo de inspección para recuperar el nombre de archivo (y la ruta) del archivo actual
Las soluciones mencionadas anteriormente también están bien. Otra solución a este problema es
Si quieres importar algo del directorio de nivel superior. Entonces,
from ...module_name import *
Además, si desea importar cualquier módulo desde el directorio principal. Entonces,
from ..module_name import *
Además, si desea importar cualquier módulo desde el directorio principal. Entonces,
from ...module_name.another_module import *
De esta manera puedes importar cualquier método particular si quieres.
No sé mucho sobre python 2.
En Python 3, la carpeta principal se puede agregar de la siguiente manera:
import sys
sys.path.append(''..'')
... y luego uno es capaz de importar módulos desde él
Para mí, el oneliner más corto y mi favorito para acceder al directorio principal es:
sys.path.append(os.path.dirname(os.getcwd()))
o:
sys.path.insert(1, os.path.dirname(os.getcwd()))
os.getcwd () devuelve el nombre del directorio de trabajo actual, os.path.dirname (directory_name) devuelve el nombre del directorio para el que se pasó.
En realidad, en mi opinión, la arquitectura del proyecto Python debería hacerse de la manera en que ningún módulo del directorio secundario utilizará ningún módulo del directorio principal. Si algo como esto sucede, vale la pena repensar el árbol del proyecto.
Otra forma es agregar el directorio padre a la variable de entorno del sistema PYTHONPATH.
Parece que el problema no está relacionado con el hecho de que el módulo esté en un directorio principal o algo así.
ptdraft
agregar el directorio que contiene ptdraft
a PYTHONPATH
Usted dijo que la import nib
funcionó con usted, lo que probablemente significa que agregó ptdraft
(no su padre) a PYTHONPATH.
Podrías usar importaciones relativas (python> = 2.5):
from ... import nib
(Novedades de Python 2.5) PEP 328: Importaciones absolutas y relativas
EDITAR : agregó otro punto ''.'' subir dos paquetes
Puede usar la ruta de acceso dependiente del sistema operativo en la "ruta de búsqueda del módulo" que se muestra en sys.path . Así que puedes agregar fácilmente el directorio padre como el siguiente
import sys
sys.path.insert(0,''..'')
Si desea agregar directorio padre-padre,
sys.path.insert(0,''../..'')
Si la adición de su carpeta de módulos a PYTHONPATH no funcionó, puede modificar la lista sys.path en su programa donde el intérprete de Python busca los módulos para importar, según la documentación de python :
Cuando se importa un módulo llamado spam , el intérprete primero busca un módulo incorporado con ese nombre. Si no se encuentra, luego busca un archivo llamado spam.py en una lista de directorios que ofrece la variable sys.path. sys.path se inicializa desde estas ubicaciones:
- el directorio que contiene el script de entrada (o el directorio actual).
- PYTHONPATH (una lista de nombres de directorio, con la misma sintaxis que la variable de shell PATH).
- el predeterminado dependiente de la instalación.
Después de la inicialización, los programas de Python pueden modificar sys.path . El directorio que contiene el script que se está ejecutando se ubica al comienzo de la ruta de búsqueda, antes de la ruta estándar de la biblioteca. Esto significa que los scripts en ese directorio se cargarán en lugar de los módulos del mismo nombre en el directorio de la biblioteca. Esto es un error a menos que el reemplazo esté destinado.
Sabiendo esto, puedes hacer lo siguiente en tu programa:
import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append(''/path/to/ptdraft/'')
# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft
Trabajar con las bibliotecas. Cree una biblioteca llamada nib, instálela con setup.py, déjela residir en los paquetes de sitio y se solucionarán sus problemas. No tienes que rellenar todo lo que haces en un solo paquete. Romperlo en pedazos.
import sys sys.path.append(''../'')
También publiqué una respuesta similar a la pregunta sobre las importaciones de paquetes para hermanos. Puedes verlo here . Lo siguiente se prueba con Python 3.6.5, (Anaconda, conda 4.5.1), máquina con Windows 10.
Solución sin sys.path -hacks o importaciones relativas.
Preparar
Asumo la misma estructura de carpetas que en la pregunta.
.
└── ptdraft
├── __init__.py
├── nib.py
└── simulations
├── __init__.py
└── life
├── __init__.py
└── life.py
Yo llamo el la carpeta raíz, y en mi caso se encuentra en C:/tmp/test_imports
.
Pasos
1) Agregar un setup.py a la carpeta raíz
El contenido de setup.py
puede ser simplemente
from setuptools import setup, find_packages
setup(name=''myproject'', version=''1.0'', packages=find_packages())
Básicamente "cualquier" setup.py funcionaría. Este es solo un ejemplo mínimo de trabajo.
2) Utilizar un entorno virtual.
Si está familiarizado con los entornos virtuales, active uno y continúe con el siguiente paso. El uso de entornos virtuales no es absolutamente necesario, pero realmente lo ayudará a largo plazo (cuando tenga más de 1 proyecto en curso ...). Los pasos más básicos son (ejecutar en la carpeta raíz)
- Crear env virtual
-
python -m venv venv
-
- Activar env virtual
-
. /venv/bin/activate
. /venv/bin/activate
(Linux) o./venv/Scripts/activate
(Win)
-
Para obtener más información sobre esto, simplemente busque en Google "tutorial virtual de python env" o similar. Probablemente nunca necesite más comandos que crear, activar y desactivar.
Una vez que haya creado y activado un entorno virtual, su consola debe indicar el nombre del entorno virtual entre paréntesis.
PS C:/tmp/test_imports> python -m venv venv
PS C:/tmp/test_imports> ./venv/Scripts/activate
(venv) PS C:/tmp/test_imports>
3) pip instala tu proyecto en estado editable
Instala tu paquete de nivel superior myproject
usando pip
. El truco es usar la bandera -e
al realizar la instalación. De esta manera, se instala en un estado editable y todas las ediciones realizadas en los archivos .py se incluirán automáticamente en el paquete instalado.
En el directorio raíz, ejecute
pip install -e .
(note el punto, significa "directorio actual")
También puede ver que se instala utilizando el pip freeze
(venv) PS C:/tmp/test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:/tmp/test_imports> pip freeze
myproject==1.0
4) Importar agregando la mainfolder
a cada importación
En este ejemplo, la mainfolder
sería ptdraft
. Esto tiene la ventaja de que no se encontrará con colisiones de nombres con otros nombres de módulos (de la biblioteca estándar de Python o módulos de terceros).
Ejemplo de uso
nib.py
def function_from_nib():
print(''I am the return value from function_from_nib!'')
vida.py
from ptdraft.nib import function_from_nib
if __name__ == ''__main__'':
function_from_nib()
Corriendo life.py
(venv) PS C:/tmp/test_imports> python ./ptdraft/simulations/life/life.py
I am the return value from function_from_nib!