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 facilitar la lectura)
¿Cómo importo el nib
módulo desde el interior del life
módulo? Espero que sea posible hacerlo sin jugar con sys.path.
Nota: El módulo principal que se está ejecutando está en la ptdraft
carpeta.
__init__.py
. S.Lott: No sé cómo verificar ...sys.path
oPYTHONPATH
respuestas y consultar la excelente respuesta de np8 . Sí, es una lectura larga. Sí, parece mucho trabajo. Pero es la única respuesta que realmente resuelve el problema de manera correcta y limpia.Respuestas:
Parece que el problema no está relacionado con que el módulo esté en un directorio principal ni nada de eso.
Necesita agregar el directorio que contiene
ptdraft
a PYTHONPATHDijiste que
import nib
funcionaba contigo, eso probablemente significa que te agregasteptdraft
(no a su padre) a PYTHONPATH.fuente
import sys
y luegosys.path.append("..\<parent_folder>")
Puede usar importaciones relativas (python> = 2.5):
(Novedades de Python 2.5) PEP 328: importaciones absolutas y relativas
EDITAR : se agregó otro punto '.' subir dos paquetes
fuente
ValueError: Attempted relative import in non-package
__init__.py
archivo.__init__.py
no es lo único que tiene que hacer: stackoverflow.com/questions/11536764/…Las importaciones relativas (como en
from .. import mymodule
) solo funcionan en un paquete. Para importar 'mymodule' que está en el directorio principal de su módulo actual:editar : el
__file__
atributo no siempre se da. En lugar de usaros.path.abspath(__file__)
, ahora sugerí usar el módulo de inspección para recuperar el nombre de archivo (y la ruta) del archivo actualfuente
sys.path.insert(1, os.path.join(sys.path[0], '..'))
parentdir
, pero en una de las rutas ya especificadassys.path
, hay otro módulo con el nombre 'mymodule'. Insertarparentdir
como el primer elemento de lasys.path
lista asegura que el móduloparentdir
se importará en su lugar.sys.path.insert(1, os.path.realpath(os.path.pardir))
también funcionaPubliqué una respuesta similar también a la pregunta sobre las importaciones de paquetes hermanos. Puedes verlo aquí .
Solución sin
sys.path
hacksResumen
packaged_stuff
)setup.py
script donde use setuptools.setup () .pip install -e <myproject_folder>
from packaged_stuff.modulename import function_name
Preparar
Asumo la misma estructura de carpetas que en la pregunta
Llamo a la
.
carpeta raíz, y en mi caso se encuentra enC:\tmp\test_imports
.Pasos
1) Agregue a
setup.py
a la carpeta raízEl contenido del
setup.py
puede ser simplementeBásicamente "cualquiera"
setup.py
funcionaría. Este es solo un ejemplo de trabajo mínimo.2) Use un entorno virtual
Si está familiarizado con los entornos virtuales, active uno y salte al siguiente paso. El uso de entornos virtuales no es absolutamente obligatorio, pero realmente lo ayudarán 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)
python -m venv venv
. /venv/bin/activate
(Linux) o./venv/Scripts/activate
(Win)Para obtener más información sobre esto, solo busque en Google "python virtualenv tutorial" 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
3) pip instala tu proyecto en estado editable
Instale su paquete de nivel superior
myproject
usandopip
. El truco es usar la-e
bandera al hacer la instalación. De esta forma, 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 .
(tenga en cuenta el punto, significa "directorio actual")También puede ver que se instala utilizando
pip freeze
4) Importar anteponiendo
mainfolder
a cada importaciónEn este ejemplo, el
mainfolder
seríaptdraft
. Esto tiene la ventaja de que no encontrará colisiones de nombres con otros nombres de módulos (desde la biblioteca estándar de Python o módulos de terceros).Ejemplo de uso
nib.py
life.py
Ejecutando life.py
fuente
sys.path
y donde el código normalmente lo instalarían los usuarios finales. Eso es mejor que lossys.path
hacks (y puede incluir el uso de PYTHONPATH en esa categoría de hacks de ruta) porque significa que el código en desarrollo debería comportarse de la misma manera para usted que para otros usuarios. Por el contrario, cuando se utilizan modificaciones de ruta, las declaraciones de importación se resolverían de una manera diferente.Puede utilizar la ruta del sistema operativo en la "ruta de búsqueda del módulo" que se encuentra en sys.path . Por lo tanto, puede agregar fácilmente el directorio principal como el siguiente
Si desea agregar el directorio padre-padre,
Esto funciona tanto en python 2 como en 3.
fuente
Si agregar la carpeta de su módulo 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, la documentación de python dice:
Sabiendo esto, puede hacer lo siguiente en su programa:
fuente
/path/to/ptdraft
tendría que ser editado. Hay soluciones que también resuelven el directorio actual del archivo y lo importan desde la carpeta principal.No sé mucho sobre python 2.
En python 3, la carpeta principal se puede agregar de la siguiente manera:
... y luego uno puede importar módulos desde él
fuente
'..'
conduce al directorio con el módulo en cuestión.Aquí hay una respuesta que es simple para que pueda ver cómo funciona, pequeña y multiplataforma.
Sólo se utiliza una función de módulos (
os
,sys
yinspect
) así debería funcionaren cualquier sistema operativo (OS), porque Python está diseñado para eso.
Código de respuesta más corto: menos líneas y variables
Para menos líneas que esta, reemplace la segunda línea con
import os.path as path, sys, inspect
,agregue
inspect.
al comienzo degetsourcefile
(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 para mi respuesta ( versión más larga )
Utiliza un ejemplo de una respuesta de desbordamiento de pila ¿Cómo obtengo la ruta del
archivo ejecutado actual en Python? para encontrar la fuente (nombre de archivo) del código en ejecución con una herramienta incorporada.
Mi código agrega una ruta de archivo a
sys.path
la lista de rutas de Pythonporque esto le permite a Python importar módulos desde 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íneacuando esa carpeta agregada tiene un módulo con el mismo nombre que otro módulo que se importa
más adelante en el programa. Debe eliminar el elemento de la 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), cualquier edición hecha para
sys.path
desaparecer.Notas sobre una variable de nombre de archivo
Mi respuesta no usa la
__file__
variable para obtener la ruta del archivo / nombre de archivo delcódigo en ejecución porque los usuarios aquí a menudo lo han descrito como poco confiable . No debe usarlo
para importar módulos de la carpeta principal en programas utilizados por otras personas.
Algunos ejemplos en los que no funciona (cita de esta pregunta de desbordamiento de pila):
• no se puede encontrar en algunas plataformas • a veces no es la ruta completa del archivo
fuente
sys.path.pop(0)
inmediatamente después de importar el módulo deseado. Sin embargo, las importaciones subsiguientes todavía fueron a esa ubicación. Por ejemplo, tengoapp/config
,app/tools
yapp/submodule/config
. Desdesubmodule
, insertoapp/
para importartools
, luego eliminoapp/
e intento importarconfig
, pero obtengo enapp/config
lugar deapp/submodule/config
.tools
las importaciones también estaba importandoconfig
desde el directorio principal. Entonces, cuando más tarde traté de hacersys.path.pop(0); import config
adentrosubmodule
, esperando llegarapp/submodule/config
, en realidad estaba entrandoapp/config
. Evidentemente, Python devuelve una versión en caché de un módulo con el mismo nombre en lugar de buscarsys.path
un módulo que coincida con ese nombre.sys.path
en este caso se estaba modificando correctamente, Python simplemente no lo estaba verificando debido a que el módulo con el mismo nombre ya se había cargado.sys.modules
... sys.modules se puede escribir. Eliminar una clave invalidará la entrada de caché para el módulo con nombre, haciendo que Python busque nuevamente en su próxima importación. Sin embargo, tenga cuidado, ya que si mantiene una referencia al objeto del módulo, invalida su caché y luego vuelve a importar, los dos objetos serán diferentes. Por el contrario,importlib.reload()
reutilizará y reiniciará el contenido del módulo ...os.path.realpath(getsourcefile(lambda:0) + "/../..")
. Obtendrá el archivo fuente actual junto con dos símbolos del directorio principal. No utilicéos.path.sep
comogetsourcefile
estaba devuelve una cadena/
incluso en Windows.realpath
se encargará de extraer dos entradas de directorio de la ruta completa (en este caso, el nombre de archivo y luego el directorio actual) que proporciona el directorio principal.Aquí hay una solución más genérica que incluye el directorio padre en sys.path (funciona para mí):
fuente
import os, sys\n sys.path.insert(0,os.path.pardir)
lo mismo, pero más allá :) (no hay avances de línea en los comentarios)os.path.pardir
no obtendrás el caminosys.path.insert()
__file__
variable que puede ser poco confiable (no siempre es la ruta completa del archivo, no funciona en todos los sistemas operativos, etc.) como los usuarios de StackOverflow han mencionado a menudo. Cambiar la respuesta para que no se incluya causará menos problemas y será más compatible. Para obtener más información, consulte stackoverflow.com/a/33532002/3787376 .Encontré que la siguiente forma funciona para importar un paquete desde el directorio principal del script. En el ejemplo, me gustaría importar funciones
env.py
desde elapp.db
paquete.fuente
sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
sys.path
en general suele ser una mala idea. Necesita alguna forma ( p . Ej .PYTHONPATH
) Para que su biblioteca sea accesible a otro código (o de lo contrario no es realmente una biblioteca); solo usa eso todo el tiempo!Las soluciones mencionadas anteriormente también están bien. Otra solución a este problema es
Si desea importar algo desde el directorio de nivel superior. Entonces,
Además, si desea importar algún módulo desde el directorio principal. Entonces,
Además, si desea importar algún módulo desde el directorio principal. Entonces,
De esta manera, puede importar cualquier método en particular si lo desea.
fuente
sys.path.append
hacks anteriores y no puedo importar mi lib de esta manera. Esto es lo que intenté hacer antes de comenzar a google :) Ok, fue estoValueError: attempted relative import beyond top-level package
Para mí, el más corto y mi línea favorita para acceder al directorio principal es:
o:
os.getcwd () devuelve el nombre del directorio de trabajo actual, os.path.dirname (nombre_directorio) devuelve el nombre del directorio para el pasado.
En realidad, en mi opinión, la arquitectura 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 sucede algo como esto, vale la pena repensar sobre el árbol del proyecto.
Otra forma es agregar el directorio padre a la variable de entorno del sistema PYTHONPATH.
fuente
En un cuaderno de Jupyter
Mientras trabaje en un Jupyter Notebook, esta breve solución puede ser útil:
Funciona incluso sin un
__init__.py
archivo.Lo probé con Anaconda3 en Linux y Windows 7.
fuente
%cd -
después de la importación, por lo que el directorio actual de la notebook no se modifica?import sys sys.path.append('../')
fuente
Cuando no se encuentra en un entorno de paquete con
__init__.py
archivos, la biblioteca pathlib (incluida con> = Python 3.4) hace que sea muy conciso e intuitivo agregar la ruta del directorio principal a PYTHONPATH:fuente
mismo tipo de estilo que la respuesta anterior, pero en menos líneas: P
el archivo devuelve la ubicación en la que está trabajando
fuente
Trabajar con bibliotecas. Haga una biblioteca llamada nib, instálela usando setup.py, deje que resida en paquetes de sitio y sus problemas se resolverán. No tienes que rellenar todo lo que haces en un solo paquete. Rómpelo en pedazos.
fuente
site-packages
cada vez que lo ejecuten en una computadora diferente.En un sistema Linux, puede crear un enlace suave desde la carpeta "vida" al archivo nib.py. Luego, simplemente puede importarlo como:
fuente