私はこのようなオブジェクトを作成しました:
company1.name = 'banana'
company1.value = 40
このオブジェクトを保存したいのですが。どうやってやるの?
標準ライブラリのpickle
name__モジュールを使うことができます。これがあなたの例への基本的な応用です:
import pickle
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
with open('company_data.pkl', 'wb') as output:
company1 = Company('banana', 40)
pickle.dump(company1, output, pickle.HIGHEST_PROTOCOL)
company2 = Company('spam', 42)
pickle.dump(company2, output, pickle.HIGHEST_PROTOCOL)
del company1
del company2
with open('company_data.pkl', 'rb') as input:
company1 = pickle.load(input)
print(company1.name) # -> banana
print(company1.value) # -> 40
company2 = pickle.load(input)
print(company2.name) # -> spam
print(company2.value) # -> 42
また、ファイルを開いて単一のオブジェクトを書き込む次のような独自の単純なユーティリティを定義することもできます。
def save_object(obj, filename):
with open(filename, 'wb') as output: # Overwrites any existing file.
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
# sample usage
save_object(company1, 'company1.pkl')
これはとても一般的な回答なので、少し高度な使用法のトピックについて触れておきます。
cPickle
name__(または_pickle
)とpickle
name__ほとんどの場合、cPickle
name__よりも実際に pickle
NAME _ モジュールを使用することをお勧めします。前者はC言語で書かれており、はるかに速いからです。微妙な違いがいくつかありますが、ほとんどの場合、それらは同等であり、Cバージョンは非常に優れたパフォーマンスを提供します。それに切り替えるのは簡単ではありませんでした。単にimport
name__ステートメントを次のように変更してください。
import cPickle as pickle
Python 3では、cPickle
name__は_pickle
と改名されましたが、pickle
name__モジュールが自動的に行うようになったため、これを行う必要はなくなりました - python 3のpickleと_pickleの違いは? 。
要約すると、Python 2と3の両方でCバージョンが使用可能な場合は、コードが always Cバージョンを使用するように、次のようなものを使用できます。
try:
import cPickle as pickle
except ModuleNotFoundError:
import pickle
pickle
name__は、 documentation に記述されているように、 protocols と呼ばれる、いくつかの異なるPython固有のフォーマットでファイルを読み書きできます。 "Protocol version 0"は ASCII そしてそれゆえに「人間が読める」バージョン> 1はバイナリで、利用可能な最高バージョンは使用されているPythonのバージョンによって異なります。デフォルトはPythonのバージョンによっても異なります。 Python 2ではデフォルトはプロトコルバージョン0
でしたが、Python 3.7ではプロトコルバージョン3
です。 Python 3.xでは、モジュールにpickle.DEFAULT_PROTOCOL
が追加されていましたが、それはPython 2には存在しません。
幸いなことに、すべての呼び出しでpickle.HIGHEST_PROTOCOL
を書くための速さがあります(それがあなたが望むものであると仮定して、あなたは通常あなたがします)、負のインデックスを通してシーケンスの最後の要素を参照するのと同じようにリテラル番号-1
を使うだけです。だから、書く代わりに:
pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)
あなただけ書くことができます:
pickle.dump(obj, output, -1)
どちらの方法でも、複数のpickle操作で使用するためにPickler
name__オブジェクトを作成した場合は、プロトコルを1回だけ指定する必要があります。
pickler = pickle.Pickler(output, -1)
pickler.dump(obj1)
pickler.dump(obj2)
etc...
注 :異なるバージョンのPythonを実行している環境では、おそらくそれらすべてが読むことができる特定のプロトコル番号を明示的に(つまりハードコードで)使うといいでしょう(後のバージョンでは一般に読むことができます)以前のものによって生成されたファイル)。
上のサンプルに示すように、pickleファイル can には任意の数のpickleオブジェクトを含めることができますが、未知数のオブジェクトがある場合は、それらをすべて可変サイズのコンテナに格納する方が簡単です。 list
name__、Tuple
name__、またはdict
name__を1回の呼び出しでそれらをすべてファイルに書き込みます。
tech_companies = [
Company('Apple', 114.18), Company('Google', 908.60), Company('Microsoft', 69.18)
]
save_object(tech_companies, 'tech_companies.pkl')
リストとその中のすべてを後で復元します。
with open('tech_companies.pkl', 'rb') as input:
tech_companies = pickle.load(input)
大きな利点は、後でロードするために保存するオブジェクトインスタンスの数を知る必要がないことです(その情報を使わずにそうすることで is 可能ですが、若干特殊なコードが必要です)。これを行うさまざまな方法の詳細については、関連する質問 pickleファイルに複数のオブジェクトを保存して読み込む? の回答を参照してください。個人的にはI@Lutz Precheltの answer が一番です。これは、ここの例に適応したものです。
class Company:
def __init__(self, name, value):
self.name = name
self.value = value
def pickled_items(filename):
""" Unpickle a file of pickled data. """
with open(filename, "rb") as f:
while True:
try:
yield pickle.load(f)
except EOFError:
break
print('Companies in pickle file:')
for company in pickled_items('company_data.pkl'):
print(' name: {}, value: {}'.format(company.name, company.value))
オブジェクトがclass
であると仮定するのはかなり強い仮定だと思います。 class
ではない場合はどうなりますか?オブジェクトがインタプリタで定義されていないという仮定もあります。インタプリタで定義されているとどうなりますか?また、属性が動的に追加された場合はどうなりますか?いくつかのpythonオブジェクトが作成後にそれらの__dict__
に追加された属性を持っているとき、pickle
はそれらの属性の追加を尊重しません(すなわち、pickle
はオブジェクト定義への参照によって直列化されるので忘れられます)。
これらすべての場合において、pickle
およびcPickle
はあなたを恐ろしく失敗させる可能性があります。
object
(任意に作成されたもの)を保存しようと思っているのなら、(オブジェクト定義に追加された、あるいはその後に)属性を持っています…dill
を使うのが最善の策です。
私たちはクラスから始めます…
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import pickle
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>> with open('company.pkl', 'wb') as f:
... pickle.dump(company1, f, pickle.HIGHEST_PROTOCOL)
...
>>>
シャットダウンして再起動してください。
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import pickle
>>> with open('company.pkl', 'rb') as f:
... company1 = pickle.load(f)
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1090, in load_global
klass = self.find_class(module, name)
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1126, in find_class
klass = getattr(mod, name)
AttributeError: 'module' object has no attribute 'Company'
>>>
おっと…pickle
はそれを処理できません。 dill
を試してみましょう。良い方法として、別のオブジェクト型(lambda
)を投入します。
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> with open('company_dill.pkl', 'wb') as f:
... dill.dump(company1, f)
... dill.dump(company2, f)
...
>>>
そして今、ファイルを読みます。
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> with open('company_dill.pkl', 'rb') as f:
... company1 = dill.load(f)
... company2 = dill.load(f)
...
>>> company1
<__main__.Company instance at 0x107909128>
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>>
できます。 pickle
が失敗し、dill
が失敗しないのは、dill
が(ほとんどの部分で)__main__
をモジュールのように扱い、また(pickle
が行うように)参照によるピッキングの代わりにクラス定義をpickle化できるためです。 dill
がlambda
を漬けることができるのは、それが名前をつけるからです…そして、酸洗いの魔法が起こり得るのです。
実際、たくさんのオブジェクトを作成した場合は特に、これらすべてのオブジェクトを簡単に保存する方法があります。 pythonセッション全体をダンプして、後で戻ってきてください。
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> class Company:
... pass
...
>>> company1 = Company()
>>> company1.name = 'banana'
>>> company1.value = 40
>>>
>>> company2 = lambda x:x
>>> company2.name = 'rhubarb'
>>> company2.value = 42
>>>
>>> dill.dump_session('dill.pkl')
>>>
今すぐあなたのコンピュータをシャットダウンし、エスプレッソか何かを楽しみに行って、そして後で戻ってくる...
Python 2.7.8 (default, Jul 13 2014, 02:29:54)
[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.
>>> import dill
>>> dill.load_session('dill.pkl')
>>> company1.name
'banana'
>>> company1.value
40
>>> company2.name
'rhubarb'
>>> company2.value
42
>>> company2
<function <lambda> at 0x1065f2938>
唯一の大きな欠点はdill
がpython標準ライブラリの一部ではないということです。あなたのサーバーにpythonパッケージをインストールできないのであれば、あなたはそれを使うことができません。
ただし、システムにpythonパッケージをインストールできる場合は、git+https://github.com/uqfoundation/dill.git@master#Egg=dill
を使用して最新のdill
を取得できます。そして、あなたはpip install dill
で最新リリース版を手に入れることができます。
あなたはあなたのために仕事をするために anycache を使うことができます。それはすべての詳細を考慮します:
pickle
モジュールを拡張してlambda
とすべてのNice pythonの機能を処理します。インスタンスを作成する関数myfunc
があるとします。
from anycache import anycache
class Company(object):
def __init__(self, name, value):
self.name = name
self.value = value
@anycache(cachedir='/path/to/your/cache')
def myfunc(name, value)
return Company(name, value)
Anycacheは最初にmyfunc
を呼び出し、ファイル名として(関数名とその引数に応じて)一意の識別子を使用して、結果をcachedir
内のファイルにピクルします。連続して実行すると、ピクルスオブジェクトがロードされます。 cachedir
がpythonの実行間で保存されている場合、pickleオブジェクトは前回のpythonの実行から取得されます。
詳細については ドキュメント を参照してください。