オブジェクトの保存と読み込み、ピクルの使用


114

pickleモジュールを使用してオブジェクトを保存およびロードしようとしています。
まず、オブジェクトを宣言します。

>>> class Fruits:pass
...
>>> banana = Fruits()

>>> banana.color = 'yellow'
>>> banana.value = 30

その後、「Fruits.obj」というファイルを開きます(以前に新しい.txtファイルを作成し、「Fruits.obj」に名前を変更しました)。

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)

これを行った後、セッションを閉じて新しいセッションを開始し、次のセッションを保存します(保存されるはずのオブジェクトにアクセスしようとします)。

file = open("Fruits.obj",'r')
object_file = pickle.load(file)

しかし、私はこのメッセージを持っています:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
ValueError: read() from the underlying stream did notreturn bytes

このメッセージがわからないのでどうすればいいのかわかりません。オブジェクト「バナナ」をロードする方法を誰かが知っていますか?ありがとうございました!

編集: あなたの一部が私が入れたと主張したように:

>>> import pickle
>>> file = open("Fruits.obj",'rb')

問題はありませんでしたが、次は

>>> object_file = pickle.load(file)

そして私はエラーがあります:

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python31\lib\pickle.py", line 1365, in load
encoding=encoding, errors=errors).load()
EOFError


回答:


74

あなたの2番目の問題については:

 Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
 File "C:\Python31\lib\pickle.py", line
 1365, in load encoding=encoding,
 errors=errors).load() EOFError

ファイルの内容を読み取った後、ファイルポインターはファイルの最後にあります-読み取るデータはありません。ファイルを最初から再度読み取るように、ファイルを巻き戻す必要があります。

file.seek(0)

ただし、通常は、コンテキストマネージャーを使用してファイルを開き、そこからデータを読み取ります。このように、ブロックの実行が完了すると、ファイルは自動的に閉じられます。これにより、ファイル操作を意味のあるチャンクに整理することもできます。

最後に、cPickleは、Cのpickleモジュールのより高速な実装です。

In [1]: import cPickle

In [2]: d = {"a": 1, "b": 2}

In [4]: with open(r"someobject.pickle", "wb") as output_file:
   ...:     cPickle.dump(d, output_file)
   ...:

# pickle_file will be closed at this point, preventing your from accessing it any further

In [5]: with open(r"someobject.pickle", "rb") as input_file:
   ...:     e = cPickle.load(input_file)
   ...:

In [7]: print e
------> print(e)
{'a': 1, 'b': 2}

これは 'd = {"a":1、 "b":2}'とはどのようなデータ構造ですか?
Peterstone

1
@Peterstone:{"a": 1, "b": 2}キー"a"とその"b"中に辞書を作成します。これは、オンラインマニュアルでは辞書表示式と呼ばれています。これdictは、Pythonで使用可能ないくつかの標準的な組み込みデータ型の1つであるtypeのオブジェクトを構築できるいくつかの異なる方法の1つにすぎません。
martineau

2
文字「r」がファイル名の前に来るのはなぜですか?私はそれをドキュメントに見ません。また、ファイル名に変数を使用することが難しくなります。
SherylHohman 2017

7
今日この回答を見て、それがPython 2.xにのみ適用されることに気づいてください。Python 3.xでは、可能な場合picklecpickle自動的にインポートされるものを直接使用する必要があります。docs.python.org/3.1/whatsnew/3.0.html#library-changes
Eskapp

41

次は私のために働きます:

class Fruits: pass

banana = Fruits()

banana.color = 'yellow'
banana.value = 30

import pickle

filehandler = open("Fruits.obj","wb")
pickle.dump(banana,filehandler)
filehandler.close()

file = open("Fruits.obj",'rb')
object_file = pickle.load(file)
file.close()

print(object_file.color, object_file.value, sep=', ')
# yellow, 30

これでうまくいきますが、私が追求しているのは、セッションを閉じて新しいセッションを開き、過去のセッションで保存したものをロードすることです。「filehandler.close()」という行を置いた後にセッションを閉じ、新しい行を開いて残りのコードを入れ、「object_file = pickle.load(file)」を置いた後、次のエラーが発生しました:トレースバック(最新の呼び出しの最後):ファイル「<pyshell#5>」、1行目、<module>内object_file = pickle.load(file)ファイル「C:\ Python31 \ lib \ pickle.py」、1365行目、ロードエンコーディング= encoding、errors = errors).load()AttributeError: 'module' object has no attribute 'Fruits'
Peterstone

3
@Peterstone:2番目のセッションでは、バイナリファイルに保存されたデータからオブジェクトを再構成できるclass Fruitsように、definedの定義が必要pickle.load()です。この種のベストプラクティスは、class Fruits定義を個別の.pyファイルに入れ(カスタムモジュールにする)、import必要に応じてそのモジュールまたはアイテムを(つまり両方のセッションで)配置することです。たとえば、それをという名前のファイルに入れると、MyDataDefs.py次のように記述できますfrom MyDataDefs import Fruits。これが不明確な場合はお知らせください。それに応じて回答を更新します。
martineau 2011年

実際、PEP 8 はモジュール名にすべて小文字を使用することを推奨しているため、最後のコメントの最後の例はmy_data_defs.pyusingを使用した名前のファイルにあるはずfrom my_data_defs import Fruitsです。
martineau 2015年

24

あなたもそれをバイナリとして読むことを忘れています。

あなたの書き込み部分には次のものがあります:

open(b"Fruits.obj","wb") # Note the wb part (Write Binary)

あなたが読んでいる部分では:

file = open("Fruits.obj",'r') # Note the r part, there should be a b too

だからそれを次のように置き換えてください:

file = open("Fruits.obj",'rb')

そしてそれはうまくいきます:)


2番目のエラーについては、ファイルを正しく閉じない/同期していないことが原因である可能性が高いです。

次のコードを試してみてください。

>>> import pickle
>>> filehandler = open(b"Fruits.obj","wb")
>>> pickle.dump(banana,filehandler)
>>> filehandler.close()

そして、これ(変更なし)を読む:

>>> import pickle
>>> file = open("Fruits.obj",'rb')
>>> object_file = pickle.load(file)

きちんとしたバージョンでは、 withステートメントます。

書き込み用:

>>> import pickle
>>> with open('Fruits.obj', 'wb') as fp:
>>>     pickle.dump(banana, fp)

読むために:

>>> import pickle
>>> with open('Fruits.obj', 'rb') as fp:
>>>     banana = pickle.load(fp)

1
withステートメントを使用するバージョンを使用しており、次のメッセージが表示されます。トレースバック(最後の最新呼び出し):ファイル "<pyshell#20>"、1行目<モジュール> print(banana.color)AttributeError: 'Fruits'オブジェクトに属性 'color'がありません
Peterstone

17

この場合、常にバイナリモードで開きます。

file = open("Fruits.obj",'rb')

6

ファイルをバイナリモードで開きませんでした。

open("Fruits.obj",'rb')

うまくいくはずです。

2番目のエラーの場合、ファイルは空である可能性が高いです。これは、誤ってファイルを空にしたか、間違ったファイル名などを使用したことを意味します。

(これは、実際にセッションを閉じたと想定しています。そうでない場合は、書き込みと読み取りの間にファイルを閉じなかったことが原因です)。

私はあなたのコードをテストしました、そしてそれはうまくいきます。


3

セッション間でクラスインスタンスを保存したいようですpickleが、これを行うには適切な方法を使用します。ただし、kleptoオブジェクトをディクショナリインターフェースに保存することを抽象化するというパッケージがあるため、オブジェクトをピクルしてファイルに保存するか(以下に示すように)、オブジェクトをピクルしてデータベースに保存するか、またはpickle use jsonまたは他の多くのオプションを使用します。についての良いことkleptoあなたがファイルに酸洗、あるいは経由で保存する方法の低レベルの詳細を覚えておく必要はありませんので、共通のインタフェースに抽象化し、それが簡単にそれを作ることです。

これは動的に追加されたクラス属性に対して機能することに注意してください。

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive 
>>> db = file_archive('fruits.txt')
>>> class Fruits: pass
... 
>>> banana = Fruits()
>>> banana.color = 'yellow'
>>> banana.value = 30
>>> 
>>> db['banana'] = banana 
>>> db.dump()
>>> 

その後、再起動します…

dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive
>>> db = file_archive('fruits.txt')
>>> db.load()
>>> 
>>> db['banana'].color
'yellow'
>>> 

Klepto python2とpython3で動作します。

ここでコードを取得:https : //github.com/uqfoundation


1

あなたはanycacheを使ってあなたのために仕事をすることができます。myfuncインスタンスを作成する関数があると仮定します。

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc()
    banana = Fruits()
    banana.color = 'yellow'
    banana.value = 30
return banana

Anycacheはmyfunc最初に呼び出し、cachedir(関数名と引数に応じて)一意の識別子をファイル名として使用して、結果をファイルにピクルします。連続して実行すると、ピクルされたオブジェクトがロードされます。

cachedirがPythonの実行間で保持される場合、ピクルされたオブジェクトは以前のPythonの実行から取得されます。

関数の引数も考慮されます。リファクタリングされた実装も同様に機能します。

from anycache import anycache

class Fruits:pass

@anycache(cachedir='/path/to/your/cache')    
def myfunc(color, value)
    fruit = Fruits()
    fruit.color = color
    fruit.value = value
return fruit
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.