2012-06-07 16 views
25

Was ist der richtige Weg, um auf Ressourcen in Python-Programmen zuzugreifen.Zugriff auf Ressourcendateien in Python

Grundsätzlich in vielen meiner Python-Modulen ich am Ende das Schreiben von Code wie folgt aus:

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

    (...) 

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

Welche OK ist aber:

  • Es brechen, wenn ich starten Python Zip-Pakete verwenden
  • Es ist Standardcode

In Java ich eine Funktion hatte, die genau tat das gleiche --- aber funktionierte sowohl wenn der Code in mehreren Ordnern lag als auch in der Datei .jar.

Gibt es solche Funktion in Python, oder gibt es ein anderes Muster, das ich verwenden könnte.

Antwort

15

Sie wollen entweder get_data in der stdlib oder pkg_resources von setuptools/distribute betrachten. Welchen Sie verwenden, hängt wahrscheinlich davon ab, ob Sie bereits distribute verwenden, um Ihren Code als Ei zu packen.

+0

OK, das ist eine pythonische Antwort. get_data sieht interessant aus, aber pkg_resources ist sehr einschüchternd, aber ich werde mich definitiv damit beschäftigen, wenn ich mit distutils arbeite, um mein Projekt zu paketieren. –

+0

Ich suche nach einer ähnlichen Lösung. 'get_data' ist großartig, aber ich brauche das dateiähnliche Objekt für diese Datei, nicht den Inhalt der Datei direkt. Gibt es einen eleganten Weg? – zegkljan

+1

@zegkljan Der pythonischste Weg besteht darin, ihn mit BytesIO (StringIO in Py2) zu umhüllen: 'file_like = BytesIO (get_data (__ package__, 'filename.dat'))' ' – cincodenada

-1

Ich denke, das zipimport Standard-Python-Modul eine Antwort sein könnte ...

EDIT: na ja, nicht die Verwendung des Moduls direkt, sondern mit sys.path wie im gezeigten Beispiel könnte ein guter Weg sein:

  • ich habe eine Zip-Datei test.zip mit einer python-Modul test und eine Datei test.foo innerhalb
  • dass für den RV-python zu testen Modul test von den test.foo bewusst sein kann Es enthält diesen Code:

c

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

-Test sieht ok:

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

So eine Lösung Schleife in Ihrem Zip-Datei sein könnten alle Python-Module, abrufen und fügen sie in sys.path; Dieses Codeelement wäre idealerweise das erste, das von Ihrer Anwendung geladen wird.

+3

Ich stimme nicht zu --- zipimport kann nichts anderes importieren als '.py [co]?' Dateien. Wie ich in der Frage gesagt habe - dieser Code wird fehlschlagen, wenn jemand versucht hat, ihn aus einem Archiv zu starten. –

+0

In der Tat, aber die 'sys.path.insert (0, '/ tmp/example.zip') gibt eine gute Idee, wie es geht ... – Emmanuel

2

Der Versuch, zu verstehen, wie wir die beiden Aspekt togather

  1. Laden für Ressourcen im nativen Dateisystem
  2. verpackt in ZIP-Dateien

Lesen durch die kurze Anleitung auf zipimport kombinieren könnte: http://www.doughellmann.com/PyMOTW/zipimport/

Ich sehe das folgende Beispiel:

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

Ich denke, dass die Ausgabe von __file__ ist „zipimport_example.zip/example_package/__init__.pyc“

müssen prüfen, wie es von innen aussieht.

Aber dann könnten wir immer etwas tun:

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

[Edit:] Ich habe versucht, das Beispiel zu arbeiten, ein bisschen besser.

Wenn das das Paket als gezippte Datei dann importiert wird, passieren zwei Dinge

  1. __file__ enthält „.zip“ drin Weg ist.
  2. __loader__ im Namensraum zur Verfügung steht

Wenn diese beiden Bedingungen erfüllt sind, dann in der Verpackung könnten Sie tun:

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

sonst wurde das Modul geladen normal und Sie können den regulären Ansatz folgen um die Datei zu laden.

+0

@jb .: Knifflige Frage. Ich muss das noch herausfinden. – pyfunc

+0

sollten Sie 'os.path.join ('example_package', 'README.txt')' verwenden, wenn Sie plattformunabhängig sein möchten – kratenko

+0

@jb: Sieht diese Lösung besser für Sie aus? – pyfunc