2009-08-13 110 views
135

Estamos trabajando con un depósito de código que se implementa tanto en Windows como en Linux, a veces en directorios diferentes. ¿Cómo debería uno de los módulos dentro del proyecto referirse a uno de los recursos que no son de Python en el proyecto (archivos CSV, etc.)?Cómo hacer referencia a rutas relativas de recursos cuando se trabaja con un depósito de código en Python

Si hacemos algo como:

thefile=open('test.csv') 

o:

thefile=open('../somedirectory/test.csv') 

que va a funcionar sólo cuando la secuencia de comandos se ejecuta desde un directorio específico, o un subconjunto de los directorios.

Lo que me gustaría hacer es algo como:

path=getBasePathOfProject()+'/somedirectory/test.csv' 
thefile=open(path) 

¿Es este el camino correcto? ¿Es posible?

Respuesta

184

Intente utilizar un nombre de archivo relativo a la ruta actual de los archivos. Ejemplo para './my_file':

fn = os.path.join(os.path.dirname(__file__), 'my_file') 
+3

Creo que esta solución sólo funciona si el recurso está en el mismo directorio del archivo de pitón, o en un subdirectorio de la misma. ¿Cómo resolverlo cuando se tiene la siguiente estructura de árbol: /Project_Root_dir /python_files_dir /Algunos más subdirectorios aquí py_file.py /recursos/ algunos subdirectorios aquí resource_file.csv – olamundo

+0

Lo sentimos, obtuve el árbol de archivos ilegibles en ese último mensaje ... segundo intento: tiene su archivo en/Project_Root_dir/python_files_dir/some_subdirs/py_file.py y tiene su archivo de recursos en/Project_Root_dir/resources/some_subdirs/resource_file.csv – olamundo

+22

Debe ser capaz de obtener al directorio padre usando join (foo, '..'). Entonces desde/root/python_files/module/myfile, use os.path.join (os.path.dirname ('__file__'), '..', '..', 'resources') – c089

1

Usted puede utilizar la estructura en __file__ variable. Contiene la ruta del archivo actual. Implementaría getBaseOfProject en un módulo en la raíz de su proyecto. Allí obtendría la ruta de __file__ y la devolvería. Este método se puede usar en cualquier lugar de su proyecto.

4
import os 
cwd = os.getcwd() 
path = os.path.join(cwd, "my_file") 
f = open(path) 

También tratar de normalizar su cwd usando os.path.abspath(os.getcwd()). Más información here.

+0

muy pocos casos de uso donde 'cwd' es la ruta de un módulo, aunque – cedbeu

9

que a menudo utilizan algo similar a esto:

import os 
DATA_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), 'datadir')) 

# if you have more paths to set, you might want to shorten this as 
here = lambda x: os.path.abspath(os.path.join(os.path.dirname(__file__), x)) 
DATA_DIR = here('datadir') 

pathjoin = os.path.join 
# ... 
# later in script 
for fn in os.listdir(DATA_DIR): 
    f = open(pathjoin(DATA_DIR, fn)) 
    # ... 

La variable

__file__ 

contiene el nombre de archivo del script se escribe ese código en, por lo que se puede hacer caminos en relación con la escritura, pero aún escrito con caminos absolutos. Funciona bastante bien por varias razones:

  • ruta es absoluta, pero aún relativa
  • el proyecto todavía se puede implementar en un recipiente con relación

pero hay que ver la compatibilidad de la plataforma - Windows 'os.pathsep es diferente de UNIX.

-1

Pasé mucho tiempo en averiguar la respuesta a esto, pero finalmente lo tengo (y en realidad es muy simple):

import sys 
import os 
sys.path.append(os.getcwd() + '/your/subfolder/of/choice') 

# now import whatever other modules you want, both the standard ones, 
# as the ones supplied in your subfolders 

Esto añadirá la ruta relativa de la subcarpeta a los directorios de pitón mirar en Es bastante rápido y sucio, pero funciona como un encanto :)

+4

Esto solo funcionará si está ejecutando el programa Python desde el mismo directorio que el archivo .py en cuestión. Y en ese caso, podría simplemente 'abrir ('su/subcarpeta/de/elección')' de todos modos. –

+3

y OP mencionó que el código debe funcionar tanto en Windows como en Linux. Esto no. – user183037

26

Si está utilizando las herramientas de configuración o distribuye (una instalación de setup.py), la forma "correcta" de acceder a estos recursos empaquetados parece estar usando package_resources.

En su caso, el ejemplo sería

import pkg_resources 
my_data = pkg_resources.resource_string(__name__, "foo.dat") 

Lo que por supuesto lee el recurso y los datos binarios leídos sería el valor de mis_datos

Si sólo tiene el nombre del archivo también se podría utilizar

resource_filename(package_or_requirement, resource_name) 

Ejemplo:

resource_filename("MyPackage","foo.dat") 

La ventaja es que está garantizado para funcionar incluso si se trata de una distribución de archivos como un huevo.

Ver http://packages.python.org/distribute/pkg_resources.html#resourcemanager-api

+3

Sé que esta es una respuesta antigua, mi forma preferida es (¿o quizás?) Usar pkg_resources, pero con la desaparición de los huevos comprimidos, ¿hay algún daño en usar '' __file__'' como en los viejos tiempos? – Pykler

+0

Este es un enfoque sólido. Incluso si la convención del huevo se va, setuptools no lo está y muchos aún están instalando deps contra repositorios git donde el huevo se construye en tiempo de ejecución – deepelement

3

En Python, las rutas son relativas al directorio de trabajo actual , que en la mayoría de los casos es el directorio desde el que se ejecuta el programa. Es probable que el directorio de trabajo actual no sea el mismo que el directorio de su archivo de módulo, por lo que utilizar una ruta relativa a su archivo de módulo actual siempre es una mala opción.

Usando ruta absoluta debe ser la mejor solución:

import os 
package_dir = os.path.dirname(os.path.abspath(__file__)) 
thefile = os.path.join(package_dir,'test.cvs') 
Cuestiones relacionadas