2009-08-11 30 views
274

Tengo un archivo llamado tester.py, ubicado en /project.Importar un archivo desde un subdirectorio?

/project tiene un subdirectorio llamado lib, con un archivo llamado BoxTime.py:

/project/tester.py 
/project/lib/BoxTime.py 

quiero importar BoxTime de tester. He intentado esto:

import lib.BoxTime 

que dio como resultado:

Traceback (most recent call last): 
    File "./tester.py", line 3, in <module> 
    import lib.BoxTime 
ImportError: No module named lib.BoxTime 

¿Alguna idea de cómo importar BoxTime del subdirectorio?

EDITAR

El __init__.py era el problema, pero no se olvide para referirse a BoxTime como lib.BoxTime, o usar:

import lib.BoxTime as BT 
... 
BT.bt_function() 

Respuesta

353

Tome un vistazo a la documentación Paquetes (Sección 6.4) aquí: http://docs.python.org/tutorial/modules.html

En resumen, debe poner un archivo en blanco llamado

__init__.py 

en el directorio "lib".

+28

porqué se siente * * hacky? Es la forma en que python marca los directorios de importación seguros/disponibles. – IAbstract

+5

No solo marca los directorios de importación seguros/disponibles, sino que también proporciona una forma de ejecutar algún código de inicialización al importar un nombre de directorio. – Sadjad

+12

Sí, esto es hacky e incluso sucio, y en mi opinión, el lenguaje no debería imponer su forma de cargar archivos a través del sistema de archivos. En PHP resolvimos el problema permitiendo que el código de usuario registre múltiples funciones de carga automática que se invocan cuando falta un namespace/clase. Luego, la comunidad produjo el estándar PSR-4 y Composer lo implementa, y hoy en día nadie tiene que preocuparse por eso. Y no hay archivos "__init__" estúpidos codificados (pero si lo desea, solo registre un enganche automático. Esta es la diferencia entre _hacky_ y _hackable_). –

11

Probar import .lib.BoxTime. Para obtener más información, lea acerca de la importación relativa en PEP 328.

+2

No creo que haya visto esa sintaxis antes. ¿Hay una razón fuerte (no) para usar este método? – tgray

+1

¿Por qué no fue esta la respuesta? Claro, si quieres hacer todo el paquete, deberías hacer eso. Pero esa no era la pregunta original. –

+0

Esto me da: ValueError: Intento de importación relativa en el paquete – Alex

19

¿Su directorio lib contiene un archivo __init__.py?

Python usa __init__.py para determinar si un directorio es un módulo.

108
  • Cree un subdirectorio llamado lib.
  • Crea un archivo vacío llamado lib\__init__.py.
  • En lib\BoxTime.py, escribir una función foo() así:

    def foo(): 
        print "foo!" 
    
  • En su código de cliente en el directorio anterior lib, escribir:

    from lib import BoxTime 
    BoxTime.foo() 
    
  • ejecutar su código de cliente.Obtendrá:

    foo! 
    

Mucho más tarde - en Linux, que se vería así:

% cd ~/tmp 
% mkdir lib 
% touch lib/__init__.py 
% cat > lib/BoxTime.py << EOF 
heredoc> def foo(): 
heredoc>  print "foo!" 
heredoc> EOF 
% tree lib 
lib 
├── BoxTime.py 
└── __init__.py 

0 directories, 2 files 
% python 
Python 2.7.6 (default, Mar 22 2014, 22:59:56) 
[GCC 4.8.2] on linux2 
Type "help", "copyright", "credits" or "license" for more information. 
>>> from lib import BoxTime 
>>> BoxTime.foo() 
foo! 
+0

¿Podría proporcionar un enlace a la documentación de Python donde se explica esto? ¡Gracias! – Zenon

+1

@Zenon, intente esto: docs.python.org/tutorial/modules.html#packages – hughdbrown

32

Usted puede tratar de insertarlo en sys.path:

sys.path.insert(0, './lib') 
import BoxTime 
+6

Esto es genial si por alguna razón no puede o no creará el archivo __init__.py. – jpihl

+1

no parece funcionar para mí (error 'No módulo ..') – minsk

+1

Funciona si ejecuta Python desde el directorio "proyecto". Los "." se interpreta en relación con su directorio de trabajo actual, no en relación con el directorio donde vive el archivo que está ejecutando. Digamos 'cd/data',' python ../ project/tester.py'. Entonces no funcionará. – morningstar

0

prueba esto:

from lib import BoxTime

+1

sin ninguna explicación, esto no es muy útil. –

6

Puedo hacer esto que básicamente cubre todos los casos (asegúrese de que tiene __init__.py en relación/ruta/a/su// lib):

import sys, os 
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/relative/path/to/your/lib/folder") 
import someFileNameWhichIsInTheFolder 
... 
somefile.foo() 


Ejemplo:
Usted tiene en su carpeta de proyecto:

/root/myproject/app.py 

que tienes en otra carpeta del proyecto:

/root/anotherproject/utils.py 
/root/anotherproject/__init__.py 

que desea utilizar /root/anotherproject/utils.py y llamar a la función foo que está en ella.

Así se escribe en app.py:

import sys, os 
sys.path.append(os.path.dirname(os.path.realpath(__file__)) + "/../anotherproject") 
import utils 

utils.foo() 
+1

si está utilizando 'os.path', probablemente quiera usar' os.path.join ((os.path.dirname (os.path.realpath (__ file __)), '..', 'anotherproject') ' en lugar de codificar el '/' en su ruta de concatenación. – cowbert

0

Crear un archivo vacío __init__.py en el subdirectorio/lib. Y agregar en el inicio del código principal

from __future__ import absolute_import 

continuación

import lib.BoxTime as BT 
... 
BT.bt_function() 

o mejor

from lib.BoxTime import bt_function 
... 
bt_function() 
Cuestiones relacionadas