2012-06-07 12 views
25

¿Cuál es la forma correcta de acceder a los recursos en los programas de Python?Forma de acceder a los archivos de recursos en python

Básicamente en muchas de mis módulos de Python que terminan la escritura de código así:

DIRNAME = os.path.split(__file__)[0] 

    (...) 

    template_file = os.path.join(DIRNAME, "template.foo") 

que está bien, pero:

  • Se romperá si voy a comenzar a utilizar los paquetes de Python zip
  • es código repetitivo

En Java que tenía una función que hizo exactamente lo mismo --- pero funcionaba tanto cuando el código estaba en un montón de carpetas como cuando estaba empaquetado en el archivo .jar.

¿Existe tal función en Python, o hay algún otro patrón que pueda usar?

Respuesta

15

Tendrá que ver usando get_data en stdlib o pkg_resources desde setuptools/distribute. El que usas probablemente depende de si ya estás usando distribuir para empaquetar tu código como un huevo.

+0

OK esta es una respuesta pitonica. get_data parece interesante, pero pkg_resources es intimidante, pero definitivamente lo investigaré cuando comience a usar distutils para empacar mi proyecto. –

+0

Estoy buscando una solución similar. 'get_data' es genial, pero necesito obtener el objeto similar a un archivo para este archivo, no el contenido del archivo directamente. ¿Hay una manera elegante? – zegkljan

+1

@zegkljan La forma más pitónica es envolverlo con BytesIO (StringIO en Py2): 'file_like = BytesIO (get_data (__ package__, 'filename.dat'))' – cincodenada

-1

supongo que el módulo de Python estándar zipimport podría ser una respuesta ...

EDIT: Bueno, no el uso del módulo directamente, pero utilizando sys.path como se muestra en el ejemplo podría ser una buena manera:

  • tengo un archivo zip test.zip con un módulo de Python test y un archivo test.foo dentro
  • para probar que para el pitón cremallera módulo test puede estar al tanto de de test.foo , Que contiene este código:

c

import os 
DIRNAME = os.path.dirname(__file__) 
if os.path.exists(os.path.join(DIRNAME, 'test.foo')): 
    print 'OK' 
else: 
    print 'KO' 

prueba se ve bien:

>>> import sys 
>>> sys.path.insert(0, r'D:\DATA\FP12210\My Documents\Outils\SVN\05_impl\2_tools\test.zip') 
>>> import test 
OK 
>>> 

Así que una solución podría ser la de bucle en el archivo zip para recuperar todos los módulos de Python, y añadir ellos en sys.path; este pedazo de código sería idealmente el primero cargado por su aplicación.

+3

No estoy de acuerdo --- zipimport no puede importar nada más que archivos '.py [co]?'. Como dije en la pregunta, este código fallará si alguien intenta ejecutarlo desde un archivo. –

+0

De hecho, pero el 'sys.path.insert (0, '/tmp/example.zip')' da una buena idea de cómo hacerlo ... – Emmanuel

2

Tratar de entender cómo podemos combinar los dos aspectos Togather

  1. de carga para los recursos en el sistema de archivos nativo
  2. empaquetadas en archivos comprimidos

lectura a través del rápido tutorial sobre zipimport: http://www.doughellmann.com/PyMOTW/zipimport/

Veo el siguiente ejemplo:

import sys 
sys.path.insert(0, 'zipimport_example.zip') 
import os 
import zipimport 
importer = zipimport.zipimporter('zipimport_example.zip') 
module = importer.load_module('example_package') 
print module.__file__ 
print module.__loader__.get_data('example_package/README.txt') 

creo que la producción de __file__ es "zipimport_example.zip/example_package/__init__.pyc"

necesidad de comprobar cómo se ve desde el interior.

Pero entonces siempre podemos hacer algo como esto:

if ".zip" in example_package.__file__: 
    ... 
    load using get_data 
else: 
    load by building the correct file path 

[Editar:] He tratado de resolver el ejemplo un poco mejor.

Si el paquete se importa como archivo comprimido entonces, ocurren dos cosas

  1. __file__ contiene ".zip" a su paso.
  2. __loader__ está disponible en el espacio de nombres

Si se cumplen entonces estas dos condiciones dentro del paquete que podría hacer:

print __loader__.get_data(os.path.join('package_name','README.txt')) 

de lo contrario el módulo fue cargado con normalidad y se puede seguir el método ordinario para cargar el archivo

+0

@jb .: Pregunta complicada. Todavía necesito resolver esto. – pyfunc

+0

debe usar 'os.path.join ('example_package', 'README.txt')' si quiere ser independiente de la plataforma – kratenko

+0

@jb: ¿Esta solución le queda mejor? – pyfunc

Cuestiones relacionadas