2016-08-24 2 views
0

Ich versuche mit dem Shelve-Python-Modul meine Session-Ausgabe zu speichern und später neu zu laden, aber ich habe festgestellt, dass wenn ich Funktionen definiert habe, bekomme ich einen Fehler in der Nachladephase. Gibt es ein Problem mit der Art, wie ich es mache? Ich habe meinen Code auf eine Antwort unter How can I save all the variables in the current python session? basiert.Speichern von Funktionen mit Shelve

Hier ist ein einfacher Code, der den Fehler reproduziert:

def test_fn(): #simple test function 
    return 

import shelve 
my_shelf = shelve.open('test_shelve','n') 

for key in globals().keys(): 
    try: 
     my_shelf[key] = globals()[key] 
    except: #__builtins__, my_shelf, and imported modules cannot be shelved. 
     pass 

my_shelf.close() 

Dann kann ich

ls -lh test_shelve* 
-rw-r--r-- 1 user group 22K Aug 24 11:16 test_shelve.bak 
-rw-r--r-- 1 user group 476K Aug 24 11:16 test_shelve.dat 
-rw-r--r-- 1 user group 22K Aug 24 11:16 test_shelve.dir 

Im Allgemeinen tun, wenn ich verlassen, in einer neuen IPython Sitzung, die ich etwas in der Lage sein zu tun wie:

import shelve 
my_shelf = shelve.open('test_shelve') 
for key in my_shelf: 
    globals()[key]=my_shelf[key] 

Dies erzeugt einen Fehler für den Schlüssel 'test_fn'. Hier ist ein Code, den Fehler zu demonstrieren:

print my_shelf['test_fn'] 
--------------------------------------------------------------------------- 
AttributeError       Traceback (most recent call last) 
<ipython-input-4-deb481380237> in <module>() 
----> 1 print my_shelf['test_fn'] 

/home/user/anaconda2/envs/main/lib/python2.7/shelve.pyc in __getitem__(self, key) 
    120   except KeyError: 
    121    f = StringIO(self.dict[key]) 
--> 122    value = Unpickler(f).load() 
    123    if self.writeback: 
    124     self.cache[key] = value 

AttributeError: 'module' object has no attribute 'test_fn' 

Natürlich ist eine Lösung wäre, Funktionen in der Sparphase ausschließen, sondern von dem, was ich gelesen habe, soll es möglich sein, sie mit dieser Methode zu restaurieren und so Ich habe mich gefragt, ob ich etwas falsch mache.

Antwort

3

Sie können nicht shelve (oder pickle, die von shelve tatsächlich verwendete Protokoll)ausführbaren Code zu speichern, nein.

Was gespeichert ist, ist eine Referenz an die Funktion (nur die Stelle, an der die Funktion wieder importiert werden kann). Code sind keine Daten, nur die Tatsache, dass Sie auf eine Funktion verwiesen haben, sind hier Daten. Pickle erwartet, dass Sie das gleiche Modul und die gleiche Funktion erneut laden können, wenn Sie die gespeicherten Informationen laden.

Das gleiche würde für Klassen gelten; Wenn Sie einen Verweis auf eine Klasse pickle oder eine Instanz einer Klasse pickle, werden nur die Informationen zum erneuten Importieren der Klasse gespeichert (um die Referenz oder die Instanz neu zu erstellen).

All dies geschieht, weil Sie bereits haben eine persistente und ladbare Darstellung dieser Funktion oder Klasse: das Modul, das sie definiert. Es ist nicht notwendig, eine weitere Kopie zu speichern.

Note that functions (built-in and user-defined) are pickled by “fully qualified” name reference, not by value. This means that only the function name is pickled, along with the name of the module the function is defined in. Neither the function’s code, nor any of its function attributes are pickled. Thus the defining module must be importable in the unpickling environment, and the module must contain the named object, otherwise an exception will be raised.

Um in etwas mehr Detail für Ihr spezielles Beispiel gehen:

wird explizit in den What can be pickled and unpickled? section Dies dokumentiert Das Hauptskript, das Python führt das Modul __main__ genannt wird, und Sie ad acta die __main__.test_fn Funktion. Was dann gespeichert wird, ist einfach eine Markierung, die signalisiert, dass ein global und der Importort referenziert wurden, also etwas in der Nähe von GLOBAL und __main__ plus test_fn gespeichert sind. Wenn die gespeicherten Daten erneut geladen werden, versucht das Modul pickle beim Anzeigen des GLOBAL-Markers den Namen test_fn vom Modul __main__ zu laden. Da Ihr zweites Skript erneut als __main__ geladen wird, aber kein test_fn global hat, schlägt das Laden der Referenz fehl.

+0

OK danke. Testet, ob das Objekt, das ich meinem my_shelf hinzufügen möchte, eine Funktion beim Speichern ist, und nur wenn es nicht hinzugefügt wird, ein guter Weg, um das Problem zu lösen? Gibt es andere Objekttypen, die Probleme verursachen könnten? – PeterW

+0

@ user3798292: Sehen Sie sich die ['pickle' Dokumentation] (https://docs.python.org/2/library/pickle.html#what-can-be-pickled-und-unpickled) an, was kann und kann ' t eingelegt werden. Ich habe diese Referenz in meine Antwort aufgenommen. –

+0

@ user3798292: anstatt alles * in Ihrem Modul * zu vertonen, warum legen Sie nicht explizit alles beiseite, was für Ihr Problem von Bedeutung ist? Explizit ist hier besser als implizit. –

Verwandte Themen