attribute: Phillie Casablanca

pickleの弱点



PythonでDBのこと(とくにslqlite)知った前、データの保存するなら、自分が定義するCSVファイルとかより、pickleを使っていました。 pickle/cPickleはPythonのオブジェクットをそのままでファイルで保存することが出来ます。

[code]
import cPickle

object_dict = {'1':'一つ','2':'二つ'}

file_obj = open('test.pkl','w')

cPickle.dump(object_dict,file_obj)
file_obj.close()

#データを読み込む場合
file_obj = open('test.pkl','r')
object_data2 = cPickle.load(file_obj)
[/code]

楽でしょう。

しかし、この間、pickleでデータを保存してみたら、データが完全に保存されなかったです。
わかるまで一日ぐらいかかったが、自分のオブジェクト(クラス)を定義した場合、メモリ上で存在しているオブジェクットしか参照しないようです。

[code]
>>> import pickle
>>>
>>> class myclass:
... myattr = None

>>> x = myclass()
>>> x.myattr = 1

>>> # これでpickleとして本尊するのはまだいいのですが。。。
>>> file_obj = open('file.pkl','w')
>>> pickle.dump(x,file_obj)

>>> recovered_x = pickle.load(file_obj)
>>> recovered_x.myattr
1
[/code]

ここで問題なくロードができましたが、セッションを閉じたら、問題になってしまう。

[code]
# 一回 exit()して、再開やってみる
>>> exit()
PS D:\> python
Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import pickle
>>>
>>> file_obj = open('file.pkl','r')
>>> recovered_x = pickle.load(file_obj)
Traceback (most recent call last):
File "", line 1, in
File "C:\python25\Lib\pickle.py", line 1370, in load
return Unpickler(file).load()
File "C:\python25\Lib\pickle.py", line 858, in load
dispatch[key](self)
File "C:\python25\Lib\pickle.py", line 1069, in load_inst
klass = self.find_class(module, name)
File "C:\python25\Lib\pickle.py", line 1126, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'myclass'
>>>
[/code]

これでできないようにみえますが、実は出来ます。
もっとのmyclassの定義が見つかっていないからだけです。
class_mod.pyというファイルにクラスの定義を保存して、同じことやってみたら、行きます。

しかし、問題はこれからです。
class_mod.pyに新しいクラスを追加します:

[class_mod.py code]
class myclass:
myattr = None

class newclass:
sub_class = myclass()
[/class_mod.py code]

これでデータを保存してみよう。

[code]
>>> import class_mod
>>> import pickle
>>>
>>> x = class_mod.newclass()
>>>
>>> x.sub_class.myattr
>>> x.sub_class.myattr = 1
>>> x.sub_class.myattr
1
>>>
>>> file_obj = open('file.pkl','w')
>>> pickle.dump(x,file_obj)
>>>
>>> exit()
PS D:\> python
Python 2.5.2 (r252:60911, Feb 21 2008, 13:11:45) [MSC v.1310 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> import pickle
>>>
>>> file_obj = open('file.pkl','r')
>>> recovered_x = pickle.load(file_obj)
>>>
>>> recovered_x.sub_class.myattr
>>>
>>> recovered_x.sub_class.myattr is None
True
>>>
[/code]

単純なクラスなら保存ができるようですが、定義しているクラスが別クラスに参照しているなら、pickleは簡単には使えないです。
今回は必要のデータをDictionaryに変換する関数を作って、そのDictionaryをPickleしています。
それでそのデータをまたクラスに記入する関数を作りました。

やっと問題がわかって、解決ができたが、これくらいかかるようだったら、最初から、Dictionaryだけを使うとかsqliteを使うとかはしました。


monkut // May 9, 2008 // 7:59 a.m.