1

次のクラスは、jsonでエンコードされたディクショナリとしてネットワークを通過できる汎用オブジェクトを提供するために実装されています。私は実際にdict(!)をjsonエンコードしようとしていますが、機能しません。

カスタムエンコーダークラスで動作することはわかっていますが、dictをエンコードするだけでなぜそれが必要なのかわかりません。

誰かがTypeErrorを説明したり、JSONEncoderをサブクラス化せずにこれをエンコードする方法を提供したりできますか?

これが悪い振る舞いです。

>>> def tree(): return CustomDict(tree)
>>> d = tree()
>>> d['one']['test']['four'] = 19
>>> d.dict
{ 'one' : { 'test': {'four': 19}}}
>>> type(d.dict)
<type 'dict'> 
>>> import json
>>> json.dumps(d.dict)
# stacktrace removed
TypeError: {'one': {'test': {'four': 19}}} is not JSON serializable
>>> normal_d = {'one': {'test': {'four': 19}}}
>>> type(normal_d)
<type 'dict'>
>>> json.dumps(normal_d)
"{'one': {'test': {'four': 19}}}"
>>> normal_d == d
True

次のことができるようになりたいです

>>>> json.dumps(dict(d))
"{'one': {'test': {'four': 19}}}"

しかし、「force it」にdictプロパティを追加しました(明らかに機能しませんでした)。今ではさらに大きな謎です。CustomDictクラスのコードは次のとおりです

class CustomDict(collections.MutableMapping):                                
    """                                                                         
    A defaultdict-like object that can also have properties and special methods 
    """                                                                         

    def __init__(self, default_type=str, *args,  **kwargs):                     
        """                                                                     
        instantiate as a default-dict (str if type not provided). Try to update 
        self with each arg, and then update self with kwargs.                                                                

        @param default_type: the type of the default dict                       
        @type default_type: type (or class)                                     
        """                                                                     
        self._type = default_type                                               
        self._store = collections.defaultdict(default_type)                     
        self._dict = {}                                                         

        for arg in args:                                                        
            if isinstance(arg, collections.MutableMapping):                     
                self.update(arg)                                                

        self.update(kwargs)                                                     

    @property                                                                   
    def dict(self):                                                             
        return self._dict                                                       

    def __contains__(self, key):                                                
        return key in self._store                                               

    def __len__(self):                                                          
        return len(self._store)                                                 

    def __iter__(self):                                                         
        return iter(self._store)                                                

    def __getitem__(self, key):                                                 
        self._dict[key] = self._store[key]                                      
        return self._store[key]                                                 

    def __setitem__(self, key, val):                                            
        self._dict[key] = val                                                   
        self._store[key] = val                                                  

    def __delitem__(self, key):                                                 
        del self._store[key]                                                    

    def __str__(self):                                                          
        return str(dict(self._store))   
4

1 に答える 1

1

dict自分のタイプを、実際にはのではなく、のサブクラスにしたいのですcollections.MutableMapping

さらに良いcollections.defaultdictことに、代わりに直接使用してください。これはすでにのサブクラスでdictあり、ツリーの「タイプ」を簡単に実装するために使用できます。

from collections import defaultdict

def Tree():
    return defaultdict(Tree)

tree = Tree()

デモンストレーション:

>>> from collections import defaultdict
>>> def Tree():
...     return defaultdict(Tree)
... 
>>> tree = Tree()
>>> tree['one']['two'] = 'foobar'
>>> tree
defaultdict(<function Tree at 0x107f40e60>, {'one': defaultdict(<function Tree at 0x107f40e60>, {'two': 'foobar'})})
>>> import json
>>> json.dumps(tree)
'{"one": {"two": "foobar"}}'

独自のメソッドと動作を追加する必要がある場合は、サブクラスdefaultdict化してそのベースに基づいて構築します。

class CustomDict(defaultdict):
    pass

これはまだのサブクラスであるdictため、jsonライブラリは特別な処理なしでそれをJSONオブジェクトに喜んで変換します。

于 2013-01-31T17:49:24.613 に答える