Importando módulos desde la carpeta padre

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 .

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 : añade otro punto ‘.’ subir dos paquetes

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

Si la adición de su carpeta de módulos a PYTHONPATH no funcionó, puede modificar la lista sys.path en su progtwig 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 syntax que la variable de shell PATH).
  • el predeterminado dependiente de la instalación.

Después de la inicialización, los progtwigs 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 módulos con el 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 progtwig:

 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 

También publiqué una respuesta similar a la pregunta sobre las importaciones de paquetes para hermanos. Puedes verlo aquí . 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

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 del 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, solo 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! 

Puede usar la ruta de acceso dependiente del SO en la “ruta de búsqueda del módulo” que se encuentra en sys.path . Para que pueda agregar fácilmente el directorio padre como sigue

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

Si desea agregar directorio padre-padre,

 sys.path.insert(0,'../..') 

No sé mucho acerca de 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

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)) 

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 stack. ¿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 quiera 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 adelante en el progtwig. Debe eliminar el elemento de lista agregado antes de la importación, no otras rutas.
Si su progtwig no importa otros módulos, es seguro no eliminar la ruta del archivo porque
después de que un progtwig 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 progtwigs utilizados por otras personas.

Algunos ejemplos en los que no funciona (cita de esta pregunta de desbordamiento de stack):

• 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

Para mí, el 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 architecture del proyecto Python debe 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.

import sys sys.path.append('../')

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)) 

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.

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

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.

En un sistema Linux, puede crear un enlace flexible desde la carpeta “life” al archivo nib.py. Entonces, simplemente puedes importarlo como:

 import nib