2017-09-02 11 views
0

なぜですかjson.loadsのみ許可object_hook,parse_float,およびparse_constantPython json.loadに配列フックとパースコールバックがありませんか?

json.loads(fp[, encoding[, cls[, object_hook[, parse_float[, parse_int[, parse_constant[, object_pairs_hook[, **kw]]]]]]]]) 

これらはすべて本質的にコールバックであり、その戻り値は解析中に使用されます。

私の意図は、これらのコールバックを使用して、コールバックパラメータを変更してJSON文字列の独自の表現を作成することでした。しかし、配列、文​​字列、ブール値のコールバックがなくても、かなり制限されているようです。 (1つのオブジェクトのみがあるので)_object_hookするだけで、単一の呼び出しで結果...

import json 

def _object_hook(d): 
    print(d) 
    return d 

json.loads('{"a": [1, [2, [3]]]}', object_hook=_object_hook) 

は、この単純な例を見てみましょう。

>>> {u'a': [1, [2, [3]]]} 

任意の深さ、ネストされた配列、配列を渡すのジョブを(再帰的に、またはおそらく幅優先/深さ優先トラバーサルを有する)のままで与えます。

続いて、文字列があまりにもいくつかの理由と例外のためのものです:

import json 

def _object_hook(o): 
    print('_object_hook', o) 
    return o 

def _parse_float(f): 
    print('_parse_float', f) 
    return f 

def _parse_int(i): 
    print('_parse_int', i) 
    return i 

def _parse_constant(c): 
    print('_parse_constant', c) 
    return c 

json.loads('{"a": [1, [2, [3.1], ["4"]]]}', 
    object_hook=_object_hook, 
    parse_int=_parse_int, 
    parse_float=_parse_float, 
    parse_constant=_parse_constant) 

...( "4" は、以下の結果に省略されている)文字列を処理する方法はありません。

('_parse_int', '1') 
('_parse_int', '2') 
('_parse_float', '3.1') 
('_object_hook', {u'a': ['1', ['2', ['3.1'], [u'4']]]}) 

おそらく私の期待は間違っています。しかし、JSON文字列をPythonの辞書やリストに解析して、それを再度カスタム形式に解析するだけでは無駄に思えました。

json.loadsを使用して残して、結果のPython表現を自分のPythonクラスに解析すると、文字列、ブール値、ヌルなどの配列フックや解析コールバックがありません。

+1

パフォーマンス。そしてフックは、JSONフォーマットの卸売替えを可能にするものではありません。 –

答えて

0

少し遅い解析を考慮したい場合は、ruamel.yamlパーサーを使用してください(免責事項:私はそのパッケージの著者です)。 YAML 1.2は、すべての実用的な目的のためにJSONのスーパーセットであるとして、あなたはConstructorをサブクラス化することができます

import sys 
from ruamel.yaml import YAML, SafeConstructor 

json_str = '{"a": [1, [2.0, True, [3, null]]]}' 


class MyConstructor(SafeConstructor): 
    def construct_yaml_null(self, node): 
     print('null') 
     data = SafeConstructor.construct_yaml_null(self, node) 
     return data 

    def construct_yaml_bool(self, node): 
     print('bool') 
     data = SafeConstructor.construct_yaml_bool(self, node) 
     return data 

    def construct_yaml_int(self, node): 
     print('int') 
     data = SafeConstructor.construct_yaml_int(self, node) 
     return data 

    def construct_yaml_float(self, node): 
     print('float') 
     data = SafeConstructor.construct_yaml_float(self, node) 
     return data 

    def construct_yaml_str(self, node): 
     print('str') 
     data = SafeConstructor.construct_yaml_str(self, node) 
     return data 

    def construct_yaml_seq(self, node): 
     print('seq') 
     for data in SafeConstructor.construct_yaml_seq(self, node): 
      pass 
     return data 

    def construct_yaml_map(self, node): 
     print('map') 
     for data in SafeConstructor.construct_yaml_map(self, node): 
      pass 
     return data 


MyConstructor.add_constructor(
    u'tag:yaml.org,2002:null', 
    MyConstructor.construct_yaml_null) 

MyConstructor.add_constructor(
    u'tag:yaml.org,2002:bool', 
    MyConstructor.construct_yaml_bool) 

MyConstructor.add_constructor(
    u'tag:yaml.org,2002:int', 
    MyConstructor.construct_yaml_int) 

MyConstructor.add_constructor(
    u'tag:yaml.org,2002:float', 
    MyConstructor.construct_yaml_float) 

MyConstructor.add_constructor(
    u'tag:yaml.org,2002:str', 
    MyConstructor.construct_yaml_str) 

MyConstructor.add_constructor(
    u'tag:yaml.org,2002:seq', 
    MyConstructor.construct_yaml_seq) 

MyConstructor.add_constructor(
    u'tag:yaml.org,2002:map', 
    MyConstructor.construct_yaml_map) 


yaml = YAML(typ='safe') 
yaml.Constructor = MyConstructor 

data = yaml.load(json_str) 
print(data) 

ちょうどあなたがしたいオブジェクトを作成し、それらを返すコードで各construct_yaml_XYZ方法でコードを置き換えます。

マッピング/ディクテーションを作成するときにループがforの「面白いビジネス」です。 (実際のYAML入力がアンカー/エイリアスを使って再帰的なデータ構造を扱うために必要な)2つのステップのプロセスをアンラップすることです。

上記出力:

map 
str 
seq 
int 
seq 
float 
bool 
seq 
int 
null 
{'a': [1, [2.0, True, [3, None]]]} 

また、低いレベルでYAMLパーサにフックすることができますが、それは実装が簡単に、おそらくわずかに速くなりません。

0

@ martijn-pietersが正しいアプローチをしていました。私はJSONを解析するためにフックを使用しようとする方向に向かっていました。それらは構文解析を増強するために存在しますが、それを置き換えるものではありません。

関連する問題