web-dev-qa-db-ja.com

Pythonで辞書を永続的に保存するエレガントな方法?

現在、ファイルの解析にコストがかかり、ほとんど更新されない〜400のキーと値のペアのディクショナリが生成されます。以前はファイルを解析する関数があり、辞書構文でテキストファイルに書き込みました(つまり、dict = {'Adam': 'Room 430', 'Bob': 'Room 404'})など、それをコピーして、解析された辞書を返すことを唯一の目的とする別の関数に貼り付けました。

したがって、そのディクショナリを使用するすべてのファイルで、その関数をインポートし、それを変数に割り当てます。変数は、そのディクショナリになります。コードを明示的にコピーして貼り付けることを含まない、よりエレガントな方法があるかどうか疑問に思いますか?データベースの種類を使用する必要はないようで、テキストファイルを使用すると、関数に追加する前に解析が正しく行われたかどうかを確認できるというメリットがありました。しかし、私は提案を受け入れます。

19
zhuyxn

それをJSONファイルにダンプして、必要な場所からロードしませんか?

import json

with open('my_dict.json', 'w') as f:
    json.dump(my_dict, f)

# elsewhere...

with open('my_dict.json') as f:
    my_dict = json.load(f)

JSONからのロードはかなり効率的です。

別のオプションは pickle を使用することですが、JSONとは異なり、JSONが生成するファイルは人間が読める形式ではないため、古い方法で気に入った視覚的な検証を失うことになります。

41
Amber

なぜこれらすべてのシリアル化メソッドを台無しにするのですか? Python dictとしてファイルに既に書き込まれています(残念ながら「dict」という名前ですが)。プログラムを変更して、より適切な変数名(おそらく「data」)でデータを書き出すか、または「カタログ」、およびファイルをPythonファイル、たとえばdata.pyとして保存します。その後、不必要なコピー/貼り付けやJSON /シェルブなどを使用せずに、実行時にデータを直接インポートできます。解析:

from data import catalog
18
PaulMcG

キーがすべて文字列である場合は、 shelve モジュールを使用できます

shelf は、永続的な辞書のようなオブジェクトです。 「dbm」データベースとの違いは、シェルフの値(キーではありません!)は基本的に任意であるということですPythonオブジェクト— pickleモジュールが処理できるものすべて。これには、ほとんどのクラスインスタンスが含まれます。再帰的なデータ型、および多くの共有サブオブジェクトを含むオブジェクトキーは通常の文字列です。

jsonは、他の言語のデータを使用する必要がある場合に適しています

4
John La Rooy

多くの場合、JSONはおそらく正しい方法です。しかし、代替手段があるかもしれません。あなたのキーと値は常に文字列のようです、そうですか? dbm / anydbm の使用を検討してください。これらは「データベース」ですが、辞書とほぼ同じように機能します。安価なデータ永続化に最適です。

>>> import anydbm
>>> dict_of_strings = anydbm.open('data', 'c')
>>> dict_of_strings['foo'] = 'bar'
>>> dict_of_strings.close()
>>> dict_of_strings = anydbm.open('data')
>>> dict_of_strings['foo']
'bar'
4
senderle

ストレージ効率が重要な場合は、PickleまたはCPickleを使用してください(実行パフォーマンスを向上させるため)。 Amberが指摘したように、Jsonを介してダンプ/ロードすることもできます。人間が読めるようになりますが、より多くのディスクを必要とします。

3
luanjunyi

データ構造はマッピングなので、shelveモジュールの使用を検討することをお勧めします。それが私の 回答というタイトルの同様の質問への回答)でした。カスタムデータベースを構築したい場合、どうすればよいですか? また、別の 回答 私の質問の使用を促進する私のサンプルコードのビット オブジェクトデータベースの取得方法

ActiveStateには、高い評価の PersistentDict レシピがあり、csv、json、pickle出力ファイル形式をサポートしています。これらの3つの形式はすべてCで実装されているため(レシピ自体は純粋なPythonですが)、かなり高速です。開いたときにファイル全体をメモリに読み込むので、問題はありません。

3
martineau

JSON(またはYAML、またはその他)のシリアライゼーションはおそらくより良いですが、すでにpython構文で辞書をテキストファイルに書き込んでいる場合は、変数名バインディングを使用すると、次のように書くことができます)代わりに.pyファイルに変換します。その場合、pythonファイルはそのままインポートして使用できます。 "辞書を返す関数"のアプローチは必要ありません。そのファイルのグローバル。例:.

# generated.py
please_dont_use_dict_as_a_variable_name = {'Adam': 'Room 430', 'Bob': 'Room 404'}

のではなく:

# manually_copied.py
def get_dict():
    return {'Adam': 'Room 430', 'Bob': 'Room 404'}

唯一の違いは、manually_copied.get_dictは毎回新しい辞書のコピーを提供するのに対し、generated.please_dont_use_dict_as_a_variable_name [1]は単一の共有オブジェクトであることです。プログラムを取得した後でプログラムの辞書を変更する場合、これは問題になるかもしれませんが、他とは独立して変更する必要がある場合は、copy.copyまたはcopy.deepcopyを使用して新しいコピーを作成できます。


[1] dictliststrintmapなどは通常、不適切な変数名と見なされます。その理由は、これらはすでに組み込みとして定義されており、非常に一般的に使用されているためです。そのため、そのような名前を付けると、少なくとも、コードを読んでいる人(しばらく離れた後もあなたを含む)が「dict」を覚えておかなければならないため、認知的不協和音が発生します。これは、通常ここで何をするかを意味します。」また、コードの一部が型を使用しようとしているため、ある時点でdictオブジェクトが呼び出し可能(または何か)でないと報告して、問題が解決するという腹立たしいバグが表示される可能性もありますdictですが、代わりにdictという名前にバインドした辞書オブジェクトを取得しています。

0
Ben

jSON方向には、simpleJSONと呼ばれるものもあります。 python jsonライブラリでjsonを初めて使用したときは、jsonライブラリが機能しませんでした。わかりませんでした。simpleJSONの方が使いやすかったです...

0
Tom