Seite 1 von 1

Anwendung von pickle und classmethods

Verfasst: Donnerstag 24. Februar 2005, 09:18
von CM
Hi

hier mal etwas Pseudo-Code einer Anwendung des Pickleprotokols, weil schon einige Male Zweifel an dessen Nützlichkeit aufgetaucht sind ;-). Dies hier beschreibt das Pickling und Unpickling von Klasseninstanzen in Verbindung mit classmethod, was u.U. einige Zeilen Code sparen und mancher grauen Zelle das Leben retten kann (wie kann ich verdammtnochmal meine Klasse einfach initialisieren??? :?):

Code: Alles auswählen

import pickle

class SomeClass:
	def __init__(self, name, somedata):
		self.name = name
		self.somedata = somedata
		#und was man sonst noch so in __init__ machen kann

	def toFile(self, fname):
		pickle.dump(self, open(fname, 'wb'), 2) #binäres Picklingprotokoll

	#Python2.4 Syntax:
	@classmethod
        # oder @staticmethod , wenn 'cls' nicht gebraucht wird
	def fromFile(cls, fname):
		return pickle.load(open(fname, 'rb'))
              #das zurückgegebene Objekt entspricht der Klasseninstanz
              #weiteres Rummachen mit cls ist also unnötig
	#oder classmethod-Definition in Python2.3 Syntax
	#fromFile = classmethod(fromFile)
kann man folgendermaßen nutzen:

Code: Alles auswählen

from SomeClass import SomeClass
x = SomeClass(name="somename",somedata="somedata")
x.toFile('test.dat')
#raus aus Python und wieder rein
from SomeClass import SomeClass
x = SomeClass.fromFile('test.dat')
Na gut, das ist nicht die einzige Anwendung und es geht auch anders - aber es ist eine mögliche Anwendung, die, wie ich finde sehr, sehr praktisch ist. Für irgendjemanden hier vielleicht auch. Würde mich freuen.

Gruß,
Christian

edit: Vorschläge vom 27.10.07 eingearbeitet.
edit: nochmals korrigiert am 28.10.07
edit: Korregiert am 29.10.07

Verfasst: Samstag 27. Oktober 2007, 17:26
von gecko
Danke für das Snippet.

Bei mir tauchte das Problem auf, dass das File im Binary mode geöffnet werden muss. Die Openbefehle sollten also mit 'wb' bzw. rb ergänzt werden.

Verfasst: Samstag 27. Oktober 2007, 19:00
von BlackJack
Und wenn die `classmethod` mit dem ersten Argument nichts anstellt kann man es auch weglassen und eine `staticmethod` daraus machen.

Verfasst: Samstag 27. Oktober 2007, 21:33
von CM
BlackJack hat geschrieben:Und wenn die `classmethod` mit dem ersten Argument nichts anstellt kann man es auch weglassen und eine `staticmethod` daraus machen.
Das ist korrekt. Aber cls kann ganz praktisch sein, will man z. B. eine Versionskontrolle machen oder einen Signalhandler zufügen (siehe http://www.python-forum.de/viewtopic.php?p=76785 ). Da ich solche Snippets nur meist mit copy & paste hier reinsetze und Dinge selektiv rauskicke zur Vereinfachung, kann es zu solchen Unstimmigkeiten kommen. Das nur als Erklärung. Danke für die Klarstellung BlackJack.

@gecko: copy & paste ist wohl auch der Grund, warum da kein 'rb' stand. Sorry. Ich habe das mal für die Zukunft, damit nicht jeder alle Anmerkungen im Thread lesen muß, angepasst ...

Gruß,
Christian

Verfasst: Sonntag 28. Oktober 2007, 12:48
von gecko
write bytes auch, oder nicht?

Verfasst: Sonntag 28. Oktober 2007, 14:32
von CM
Nein, die gegenwärtige Version sollte jetzt aber stimmig sein *hust* ...
Siehe auch http://docs.python.org/lib/node317.html

Verfasst: Sonntag 28. Oktober 2007, 16:10
von BlackJack
Du musst sowohl beim Lesen als auch beim Schreiben mit 'rb' bzw. 'wb' öffnen! Egal bei welcher Protokollversion.

Verfasst: Sonntag 28. Oktober 2007, 16:21
von CM
Das ist nicht korrekt. Das oben stehende Skript ist mittlerweile (tja, ...) getestet. Wichtig ist - und das steht auch so in der Doku - das das Fileobjekt eine write-Methode hat. Mehr ist nicht von Nöten. Protokoll 2 ist genauso zu verwenden, wie ich es gezeigt habe (jedenfalls ab Python > 2.4). Probiert es aus.

Konkret gemacht habe ich:

Code: Alles auswählen

import pickle

class Someclass:
    def __init__(self, name, somedata):
        self.name = name
        self.somedata = somedata
        #und was man sonst noch so in __init__ machen kann

    def tofile(self, fname):
        pickle.dump(self, open(fname, 'w'), 2) 

    @staticmethod
    def fromfile(fname):
        return pickle.load(open(fname))

x = Someclass('bla', 3)
x.tofile('dump.dat')
aufgerufen und dann

Code: Alles auswählen

In [1]: from test import Someclass

In [2]: x = Someclass.fromfile('dump.dat')

In [3]: x
Out[3]: <test.Someclass instance at 0xb78e3f6c>

In [4]: x.name
Out[4]: 'bla'

In [5]: x.somedata
Out[5]: 3
Unter Python 2.5.1 (Linux). Ist zwar redundant, aber ...

Verfasst: Sonntag 28. Oktober 2007, 16:39
von BlackJack
Binäre Dateien müssen immer mit 'b' geöffnet werden sonst kann Müll dabei herauskommen. Das Skript würde ich nicht als getestet ansehen. Insbesondere nicht wenn Linux verwendet wurde, weil hier 'b' oder nicht 'b' keinen Unterschied macht. Speicher mal ohne das 'b' unter Windows und versuch dass dann unter Linux zu laden oder umgekehrt. Oder wahlweise auch mit MacOS.

Auch das Pickle-"Textprotokoll" ist ein Binärprotokoll, das eben nur Bytewerte im ASCII-Bereich enthält. Es erwartet aber genau ein "Trennbyte" mit dem Wert 10, egal unter welchem Betriebssystem! Wenn es etwas anderes bekommt, funktioniert das entpicklen nicht mehr.

Verfasst: Montag 29. Oktober 2007, 18:35
von CM
Jepp, irgendwie erinnere ich mich denselben Fehler schon einmal gemacht zu haben. Peinlich das.

Danke nochmals,
Christian