5

標準の JSON 機能を使用して、定期的に JSON ファイルを Python にダンプおよびロードするアプリケーションがあります。

早い段階で、読み込まれた JSON データを辞書ではなくオブジェクトとして操作する方がはるかに便利であると判断しました。[]これは、ディクショナリ キー ルックアップの表記法とは対照的に、「ドット」メンバー アクセスの利便性に帰着します。Javascript の利点の 1 つは、辞書検索とメンバー データ アクセスの間に実際の違いがないことです (これが、JSON が Javascript に特に適している理由だと思います)。しかし、Python では、辞書キーとオブジェクト データ メンバーは別物です。

object_hookしたがって、私たちの解決策は、関数を使用して辞書の代わりにオブジェクトを返すカスタム JSON デコーダーを使用することでした。

そして、私たちは幸せに暮らしました... この設計上の決定が間違いであることが判明するまで. ご覧のとおり、JSON ダンプ ファイルはかなり大きくなりました (> 400 MB)。私の知る限り、標準の Python 3 JSON 機能はネイティブ コードを使用して実際の解析を行うため、非常に高速です。ただし、 customobject_hookを指定した場合でも、デコードされた JSON オブジェクトごとに解釈されたバイト コードを実行する必要があります。これにより、処理が大幅に遅くなります。それがなければobject_hook、400 MB のファイル全体をデコードするのに約 20 秒しかかかりません。しかし、フックを使用すると、30 分以上かかります。

したがって、この時点で 2 つのオプションが思い浮かびますが、どちらもあまり快適ではありません。1 つは、"ドット" メンバー データ アクセスを使用する便利さを忘れて、Python 辞書だけを使用することです。(これは、かなりの量のコードを変更することを意味します。) もう 1 つは、C 拡張モジュールを作成し、それを として使用して、object_hook速度が向上するかどうかを確認することです。

私が考えていないより良い解決策があるかどうか疑問に思っています-おそらく、最初はPython辞書にデコードしながら、「ドット」メンバーへのアクセスを取得するより簡単な方法です。

この問題に対する提案、解決策はありますか?

4

3 に答える 3

3

object_hook を使用する代わりに、json に辞書を返させ、その辞書を名前付きタプルにダンプすることができます。

このようなもの:

from collections import namedtuple
result = json.parse(data)
JsonData = namedtuple("JsonData", result.keys())
jsondata = JsonData(**result)

速度はわかりませんが、試してみる価値はあります。

于 2012-09-13T17:44:42.277 に答える
0

返されたネイティブ JSON モジュールの dict を使用して、ドット アクセスを提供するオブジェクトでラップするのはどうですか?

次のようなことができます:

class DictWrap(object):

def __init__(self, d):
    self.__d = d

def __getattr__(self, attr):
    try:
        return self.__d[attr]
    except KeyError:
        raise AttributeError


dw = DictWrap({"a": "foo", "b": "bar"})

print dw.a, dw.b // foo bar
print dw.c // AttributeError

編集: Lennart Regebroの答えを見たところです。

于 2012-09-13T19:41:10.110 に答える
0

使い方次第です。

Lennart Regebro ソリューションは、単純な辞書の場合に完全に機能します (これはおそらくあなたの場合には当てはまりません)。それ以外の場合は、再帰的なソリューションを実装する必要があります。ただし、この場合、python は json 内の各辞書のクラスを作成します。

nemoのソリューションはより「怠惰」/「オンデマンド」であるため、辞書の各フィールドを使用しない場合は、nemoのソリューションを使用します。ただし、ネストされた辞書と配列については変更してください。

def __getattr__(self, attr):
  ...
  if isinstance(self.__d[attr], dict):
    return DictWrap(self.__d[attr])

  elif isinstance(self.__d[attr], list):
    return ListWrap(self.__d[attr])    # and create similar wrapper for List.
  ...

プレーンな辞書の別の解決策は次のとおりです。

class JsonData(object):pass

data = JsonData()
data.__dict__.update(json.parse(data))
于 2012-09-14T01:04:27.787 に答える