2012-06-07 11 views
25

Qual è il modo corretto per accedere alle risorse nei programmi python.Modo per accedere ai file di risorse in python

sostanza in molti dei miei moduli Python io alla fine scrivere codice così:

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

    (...) 

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

che è ok ma:

  • Si romperà se inizierò a usare pacchetti python zip
  • è codice standard

In Java ho avuto una funzione che ha fatto esattamente lo stesso --- ma ha funzionato sia quando il codice giaceva in un mucchio di cartelle e quando è stato impacchettato nel file .jar.

Esiste una tale funzione in Python, o c'è qualche altro schema che potrei usare.

risposta

15

Si consiglia di utilizzare get_data nello stdlib o pkg_resources da setuptools/distribute. Quello che usi probabilmente dipende dal fatto che tu stia già utilizzando distribuire per impacchettare il tuo codice come un uovo.

+0

OK questa è una risposta pitoniosa. get_data sembra interessante, ma pkg_resources è un modo per intimidire, ma cercherò in modo esauriente di esaminarlo quando inizierò a usare distutils per impacchettare il mio progetto. –

+0

Sto cercando una soluzione simile. 'get_data' è ottimo ma ho bisogno di ottenere l'oggetto simile a un file per questo file, non il contenuto del file direttamente. C'è un modo elegante? – zegkljan

+1

@zegkljan Il modo più cortese è di avvolgerlo con BytesIO (StringIO in Py2): 'file_like = BytesIO (get_data (__ package__, 'filename.dat'))' – cincodenada

-1

immagino il modulo standard di Python zipimport potrebbe essere una risposta ...

EDIT: bene, non l'uso del modulo direttamente, ma utilizzando sys.path come mostrato nell'esempio potrebbe essere un buon modo:

  • ho un file zip test.zip con un modulo python test e un file test.foo all'interno
  • per verificare che per il pitone con zip modulo test può essere a conoscenza di test.foo , Contiene questo codice:

c

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

test sembra ok:

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

Quindi una soluzione potrebbe essere quella di ciclo nel file zip per recuperare tutti i moduli Python, e aggiungere loro in sys.path; questo pezzo di codice sarebbe idealmente il primo caricato dalla tua applicazione.

+3

Non sono d'accordo --- zipimport non può importare altro che i file '.py [co]?'. Così come ho affermato nella domanda --- questo codice fallirà se qualcuno ha cercato di eseguirlo da un archivio. –

+0

Infatti, ma 'sys.path.insert (0, '/tmp/example.zip')' dà una buona idea di come fare ... – Emmanuel

2

Cercando di capire come si potrebbe combinare i due aspetti togather

  1. di carico per le risorse nel file system nativo
  2. Confezionato in file zippati

lettura attraverso il breve tutorial su zipimport: http://www.doughellmann.com/PyMOTW/zipimport/

Vedo il seguente esempio:

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') 

Penso che la produzione di __FILE__ è "zipimport_example.zip/example_package/__init__.pyc"

bisogno di verificare come appare da dentro.

Ma allora potremmo sempre fare qualcosa di simile:

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

[Edit:] Ho cercato di lavorare fuori l'esempio un po 'meglio.

Se il pacchetto viene importato come file zippato poi, due cose accadono

  1. __FILE__ contiene ".zip" nel suo percorso.
  2. __loader__ è disponibile nello spazio dei nomi

Se queste due condizioni sono soddisfatte, allora all'interno del pacchetto che si possa fare:

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

altrimenti il ​​modulo è stato caricato normalmente e si può seguire il metodo ordinario per caricare il file.

+0

@jb .: domanda ingannevole. Devo ancora lavorare su questo. – pyfunc

+0

dovresti usare 'os.path.join ('example_package', 'README.txt')' se vuoi essere indipendente dalla piattaforma – kratenko

+0

@jb: questa soluzione ti sembra migliore. – pyfunc

Problemi correlati