2011-12-06 8 views
5

Tengo mi código python en una carpeta llamada "proyecto", por lo que mis archivos de código están en project/*. Py. Quiero tener submódulos dentro de él, p.pythonic module organization - ¿cómo hacer referencia a los archivos en el directorio raíz?

project/code.py # where code lives 
project/mymodule1 # where more code lives 
project/mymodule2 

cada directorio módulo tiene su propio init archivo .py, por ejemplo,

project/mymodule1/__init__.py 

supongamos que tengo un archivo "test.py" dentro mymodule1 (proyecto/mymodule1/test.py) y me gustaría hacer referencia a algo de "código", por ejemplo, importar la función "myfunc"

== project/mymodule1/test.py == 
from code import myfunc 

el problema es que el "código" no se encontrará a menos que el usuario ha colocado el directorio "/ Proyecto de" en su PYTHONPATH. ¿Hay alguna forma de evitar esto y utilizar algún tipo de "ruta relativa" para importar myfunc, p.

from ../code import myfunc 

básicamente, no quiero obligar a los usuarios del código de alterar el PYTHONPATH a menos que pueda hacerlo mediante programación para ellos desde dentro de mi guión. Me gustaría que funcione de la caja.

¿Cómo se puede hacer esto? cualquiera de las soluciones es buena: alterar PYTHONPATH mediante programación, o más idealmente, referirme a "código" usando algún tipo de importación relativa, ya que aunque no sé dónde vive "project/code.py" en la computadora del usuario, sé dónde es relativo a "myfunc".

EDITAR: ¿Alguien puede mostrar el ejemplo correcto de importación dentro del paquete? He intentado, desde "mymodule1" hacer:

from .. import foo 

donde "foo" está en code.py pero no funciona. Tengo init .py en mymodule1, por lo que:

project/code.py 
project/mymodule1/__init__.py 
project/mymodule1/module1_code.py 

donde module1_code.py intenta importar foo, una función definida en "code.py".

EDITAR: La principal confusión que todavía tengo es que incluso después de adoptar el ejemplo dado en respuesta a mi mensaje, mostrando la jerarquía de proyecto/sub1/prueba, todavía no puede "cd" en sub1 y hacer "python test.py "y haz que funcione". El usuario debe estar en el directorio que contiene "project" y hacer "import project.sub1.test". Me gustaría que esto funcione independientemente del directorio en el que se encuentre el usuario. El usuario en este caso debe ejecutar el archivo "test.py", que vive en el proyecto/sub1 /. Por lo que el caso de prueba es:

$ cd project/sub1 
$ python test.py 

que produce el error:

ValueError: Attempted relative import in non-package 

¿Cómo puede ser fijo?

gracias.

+0

¿'code.py' también está importando' mymodule1/test.py'? Si es así, querrás ver reorganizar tu código. Las importaciones circulares deben evitarse si es posible. – Wilduck

Respuesta

3

Esto es posible en Python 2.5 y superior. Consulte los documentos en Intra-Package References.

Un par de cosas a tener en cuenta:

Si tiene la intención de que sus usuarios instalar su paquete en algún lugar, por ejemplo usando distutils o setuptools, entonces project es probable que ya en la ruta de búsqueda, y se puede cambie la importación relativa a from project.code import ... o similar.

En el caso de que sus usuarios instalen su paquete en un directorio no estándar (por ejemplo, su directorio principal, en otro lugar que no esté en sys.path, etc.), mi opinión es que genera menos confusión para instruir al usuario para modificar PYTHONPATH en lugar de cambiar programáticamente sys.path.

En el caso en que no pretendas que tus usuarios instalen tu código, por ejemplo, simplemente desmarcarán la fuente, enviarán una copia de seguridad al directorio padre de project y ejecutarán una secuencia de comandos, y luego -las referencias de paquetes y las importaciones relativas probablemente funcionen bien.

EDITAR: por solicitud, he aquí un ejemplo:

presentación de embalaje Supongamos que es el siguiente:

project/ 
    __init__.py (empty) 
    code.py 
    sub1/ 
     __init__.py (empty) 
     test.py 

Ahora, el contenido de project/code.py son:

# code.py (module that resides in main "project" package) 

def foo(): 
    print "this is code.foo" 

Y, los contenidos de project/sub1/test.py son:

# test.py (module that resides in "sub1" subpackage of main "project" package) 

from ..code import foo 
foo() 

Así, test.py importa el nombre foo de la ruta relativa ..code, que utiliza referencias intra-paquete para hacernos llegar al módulo code.py dentro del padres (esa es la parte ..) del sub1.test paquete donde estamos ejecutando desde.

Para probar esto:

shell$ (cd to directory where "project" package is located) 
shell$ python 
Python 2.6.1 (r261:67515, Aug 2 2010, 20:10:18) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> import project.sub1.test 
this is code.foo 

Tenga en cuenta que el doble punto en la sintaxis from .. import X sólo se llega al paquete principal, pero se puede especificar módulos dentro de ese paquete.

En otras palabras, from .. import X en este caso es equivalente a from project import X, y por lo tanto X debe ser o bien un módulo en project o una clase/función/nombre dentro de project/__init__.py.

Por lo tanto, from ..code import X es equivalente a from project.code import X.

+0

¿Puede alguien mostrar el ejemplo correcto de importación dentro del paquete? Intenté, desde "mymodule1" hacer: from .. import foo, donde "foo" está en code.py pero no funciona. Tengo __init__.py en mymodule1 – user248237dfsf

+0

@ user248237: vea mi respuesta modificada incluyendo un ejemplo. La principal diferencia es que 'from .. import foo' es equivalente a buscar' project/__ init __. Py', no 'code.py'. – bjlaub

+1

lo que no entiendo es por qué si usted hace un cd en "sub1" y lo hace: python test.py, obtiene el error "ValueError: Intento de importación relativa en no-paquete" – user248237dfsf

1

La mejor manera de evitar esto es mantener todo el código en una carpeta src o mejor denominarlo en su proyecto, p.myproject y tener un __init__.py allí, por lo que puede hacer esto

from myproject import code 

por lo que su estructura de carpetas sería

project 
    main.py 
    myproject 
     __init__.py 
     code.py 
     module1 
     module2 

main.py o el nombre que le dan no debería tener mucho código, se debe conseguir módulo requerido desde myproject y ejecútelo, por ejemplo

from myproject import myapp 
myapp.run() 

ver un buen article sobre cómo organizar su proyecto de pitón.

+0

que no resuelve el problema - cómo ¿El código de module1 puede llamar cosas definidas en sentido ascendente? en padres principales? – user248237dfsf

+0

myproject estará en la ruta de Python y todos los módulos pueden importar cualquier módulo, p. 'from myproject.module1 import xxx' –

+0

1) Creo que quiere decir que 'project' estará en PYTHONPATH, no 'myproject', y (2) No, no lo hará si el proceso se inició usando 'python myproject/code.py' , que es la situación del OP. Su pregunta aún no se ha resuelto, en mi humilde opinión –

Cuestiones relacionadas