web-dev-qa-db-ja.com

ネストしたPython辞書をオブジェクトに変換しますか?

いくつかの入れ子になった辞書とリストを持つ辞書の属性アクセスを使ってデータを取得するための洗練された方法を探しています(つまり、JavaScriptスタイルのオブジェクト構文)。

例えば:

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

このようにアクセス可能であるべきです:

>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar

私は、これが再帰なしでは不可能であると思うが、ディクテーションのためのオブジェクトスタイルを得るための良い方法は何だろうか?

489
Marc

更新:Python 2.6以降では、 namedtuple データ構造がニーズに合っているかどうかを検討してください。

>>> from collections import namedtuple
>>> MyStruct = namedtuple('MyStruct', 'a b d')
>>> s = MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s
MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s.a
1
>>> s.b
{'c': 2}
>>> s.c
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyStruct' object has no attribute 'c'
>>> s.d
['hi']

代替案(元の回答内容)は次のとおりです。

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

その後、あなたが使用することができます:

>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2
617
Eli Bendersky
class obj(object):
    def __init__(self, d):
        for a, b in d.items():
            if isinstance(b, (list, Tuple)):
               setattr(self, a, [obj(x) if isinstance(x, dict) else x for x in b])
            else:
               setattr(self, a, obj(b) if isinstance(b, dict) else b)

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = obj(d)
>>> x.b.c
2
>>> x.d[1].foo
'bar'
98
Nadia Alramli

驚くべきことに、だれも を述べていません。このライブラリは、辞書オブジェクトへの属性スタイルのアクセスを提供することだけを目的としており、OPが望んでいることを正確に行います。デモンストレーション:

>>> from bunch import bunchify
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = bunchify(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'

Python 3ライブラリは で入手できます。https://github.com/Infinidat/munch - クレジットは

86
kontinuity
x = type('new_dict', (object,), d)

それからこれに再帰を追加すれば完了です。

editこれが私がそれを実装する方法です:

>>> d
{'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> def obj_dic(d):
    top = type('new', (object,), d)
    seqs = Tuple, list, set, frozenset
    for i, j in d.items():
        if isinstance(j, dict):
            setattr(top, i, obj_dic(j))
        Elif isinstance(j, seqs):
            setattr(top, i, 
                type(j)(obj_dic(sj) if isinstance(sj, dict) else sj for sj in j))
        else:
            setattr(top, i, j)
    return top

>>> x = obj_dic(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
57
SilentGhost

namedtuple という名前のコレクションヘルパーがあります。

from collections import namedtuple

d_named = namedtuple('Struct', d.keys())(*d.values())

In [7]: d_named
Out[7]: Struct(a=1, b={'c': 2}, d=['hi', {'foo': 'bar'}])

In [8]: d_named.a
Out[8]: 1
46
umbrae

私が前の例の最も良い面であると感じるものを取って、これが私が思い付いたものです:

class Struct:
  '''The recursive class for building and representing objects with.'''
  def __init__(self, obj):
    for k, v in obj.iteritems():
      if isinstance(v, dict):
        setattr(self, k, Struct(v))
      else:
        setattr(self, k, v)
  def __getitem__(self, val):
    return self.__dict__[val]
  def __repr__(self):
    return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for
      (k, v) in self.__dict__.iteritems()))
30
andyvanee
class Struct(object):
    """Comment removed"""
    def __init__(self, data):
        for name, value in data.iteritems():
            setattr(self, name, self._wrap(value))

    def _wrap(self, value):
        if isinstance(value, (Tuple, list, set, frozenset)): 
            return type(value)([self._wrap(v) for v in value])
        else:
            return Struct(value) if isinstance(value, dict) else value

任意の深さの任意のsequence/dict/value構造と共に使用できます。

28
XEye

あなたの辞書がjson.loads()から来ている場合は、1行で(辞書ではなく)代わりにオブジェクトにすることができます。

import json
from collections import namedtuple

json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))

JSONデータをPythonオブジェクト に変換する方法も参照してください。

26
DS.

オブジェクトとして(または難しいキーの辞書として)辞書キーにアクセスしたい場合は、それを再帰的に実行し、元の辞書を更新することもできます。

class Dictate(object):
    """Object view of a dict, updating the passed in dict when values are set
    or deleted. "Dictate" the contents of a dict...: """

    def __init__(self, d):
        # since __setattr__ is overridden, self.__dict = d doesn't work
        object.__setattr__(self, '_Dictate__dict', d)

    # Dictionary-like access / updates
    def __getitem__(self, name):
        value = self.__dict[name]
        if isinstance(value, dict):  # recursively view sub-dicts as objects
            value = Dictate(value)
        return value

    def __setitem__(self, name, value):
        self.__dict[name] = value
    def __delitem__(self, name):
        del self.__dict[name]

    # Object-like access / updates
    def __getattr__(self, name):
        return self[name]

    def __setattr__(self, name, value):
        self[name] = value
    def __delattr__(self, name):
        del self[name]

    def __repr__(self):
        return "%s(%r)" % (type(self).__name__, self.__dict)
    def __str__(self):
        return str(self.__dict)

使用例

d = {'a': 'b', 1: 2}
dd = Dictate(d)
assert dd.a == 'b'  # Access like an object
assert dd[1] == 2  # Access like a dict
# Updates affect d
dd.c = 'd'
assert d['c'] == 'd'
del dd.a
del dd[1]
# Inner dicts are mapped
dd.e = {}
dd.e.f = 'g'
assert dd['e'].f == 'g'
assert d == {'c': 'd', 'e': {'f': 'g'}}
14
user1783597
>>> def dict2obj(d):
        if isinstance(d, list):
            d = [dict2obj(x) for x in d]
        if not isinstance(d, dict):
            return d
        class C(object):
            pass
        o = C()
        for k in d:
            o.__dict__[k] = dict2obj(d[k])
        return o


>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'
13
Anon

私は AttrDictBunch の両方のライブラリを試してみました私の用途には遅すぎます。友人と私が調べたところ、これらのライブラリを書くための主な方法は、ネストされたオブジェクトを通してライブラリを積極的に再帰させ、辞書オブジェクトのコピーを作成することです。これを念頭に置いて、2つの重要な変更を加えました。 1)属性を遅延ロードした2)辞書オブジェクトのコピーを作成する代わりに、軽量プロキシオブジェクトのコピーを作成します。これが最後の実装です。このコードを使用することによるパフォーマンスの向上は驚くべきものです。 AttrDictまたはBunchを使用する場合、これら2つのライブラリだけで、それぞれ私の要求時間の1/2と1/3を消費しました(what !?)。このコードは、その時間をほとんど何もない(0.5msの範囲のどこかに)まで減らしました。もちろんこれはあなたのニーズ次第ですが、あなたがコードの中でこの機能をかなり使っているのなら、絶対にこんな単純なものを使ってください。

class DictProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

    def __getattr__(self, key):
        try:
            return wrap(getattr(self.obj, key))
        except AttributeError:
            try:
                return self[key]
            except KeyError:
                raise AttributeError(key)

    # you probably also want to proxy important list properties along like
    # items(), iteritems() and __len__

class ListProxy(object):
    def __init__(self, obj):
        self.obj = obj

    def __getitem__(self, key):
        return wrap(self.obj[key])

    # you probably also want to proxy important list properties along like
    # __iter__ and __len__

def wrap(value):
    if isinstance(value, dict):
        return DictProxy(value)
    if isinstance(value, (Tuple, list)):
        return ListProxy(value)
    return value

元の実装 はこちらhttps://stackoverflow.com/users/704327/michael-merickel .

もう1つ注意しなければならないのは、この実装は非常に単純であり、必要なメソッドをすべて実装しているわけではないということです。 DictProxyまたはListProxyオブジェクトに必要に応じてそれらを書く必要があります。

9
JayD3e

x.__dict__.update(d)はうまくいくはずです。

7
Alex Rodrigues

これであなたは始められるでしょう:

class dict2obj(object):
    def __init__(self, d):
        self.__dict__['d'] = d

    def __getattr__(self, key):
        value = self.__dict__['d'][key]
        if type(value) == type({}):
            return dict2obj(value)

        return value

d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

x = dict2obj(d)
print x.a
print x.b.c
print x.d[1].foo

リストではまだうまくいきません。リストをUserListでラップし、辞書をラップするために__getitem__をオーバーロードする必要があります。

6
Aaron Digulla

先ほど使用した解決策Ialmostについて説明します。しかし、最初に、私がしなかった理由は、次のコードという事実によって説明されます。

d = {'from': 1}
x = dict2obj(d)

print x.from

このエラーを与えます:

  File "test.py", line 20
    print x.from == 1
                ^
SyntaxError: invalid syntax

"from"はPythonのキーワードなので、許可できない特定の辞書キーがあります。


今私の解決策はそれらの名前を直接使用することによって辞書項目へのアクセスを可能にします。しかし、それはまたあなたが "辞書の意味論"を使うことを可能にします。使用例のコードは次のとおりです。

class dict2obj(dict):
    def __init__(self, dict_):
        super(dict2obj, self).__init__(dict_)
        for key in self:
            item = self[key]
            if isinstance(item, list):
                for idx, it in enumerate(item):
                    if isinstance(it, dict):
                        item[idx] = dict2obj(it)
            Elif isinstance(item, dict):
                self[key] = dict2obj(item)

    def __getattr__(self, key):
        return self[key]

d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

x = dict2obj(d)

assert x.a == x['a'] == 1
assert x.b.c == x['b']['c'] == 2
assert x.d[1].foo == x['d'][1]['foo'] == "bar"
4
Dawie Strauss

標準ライブラリのjsonモジュールカスタムオブジェクトフックで利用できます。

import json

class obj(object):
    def __init__(self, dict_):
        self.__dict__.update(dict_)

def dict2obj(d):
    return json.loads(json.dumps(d), object_hook=obj)

使用例

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> o = dict2obj(d)
>>> o.a
1
>>> o.b.c
2
>>> o.d[0]
u'hi'
>>> o.d[1].foo
u'bar'

そしてそれはnamedtupleのように厳密に読み取り専用ではない、すなわち値を変更することができます - 構造ではありません:

>>> o.b.c = 3
>>> o.b.c
3
4
Vanni Totaro

昔のQ&Aですが、話が分からなくなりました。再帰的な口述について誰も話していないようです。これは私のコードです:

#!/usr/bin/env python

class Object( dict ):
    def __init__( self, data = None ):
        super( Object, self ).__init__()
        if data:
            self.__update( data, {} )

    def __update( self, data, did ):
        dataid = id(data)
        did[ dataid ] = self

        for k in data:
            dkid = id(data[k])
            if did.has_key(dkid):
                self[k] = did[dkid]
            Elif isinstance( data[k], Object ):
                self[k] = data[k]
            Elif isinstance( data[k], dict ):
                obj = Object()
                obj.__update( data[k], did )
                self[k] = obj
                obj = None
            else:
                self[k] = data[k]

    def __getattr__( self, key ):
        return self.get( key, None )

    def __setattr__( self, key, value ):
        if isinstance(value,dict):
            self[key] = Object( value )
        else:
            self[key] = value

    def update( self, *args ):
        for obj in args:
            for k in obj:
                if isinstance(obj[k],dict):
                    self[k] = Object( obj[k] )
                else:
                    self[k] = obj[k]
        return self

    def merge( self, *args ):
        for obj in args:
            for k in obj:
                if self.has_key(k):
                    if isinstance(self[k],list) and isinstance(obj[k],list):
                        self[k] += obj[k]
                    Elif isinstance(self[k],list):
                        self[k].append( obj[k] )
                    Elif isinstance(obj[k],list):
                        self[k] = [self[k]] + obj[k]
                    Elif isinstance(self[k],Object) and isinstance(obj[k],Object):
                        self[k].merge( obj[k] )
                    Elif isinstance(self[k],Object) and isinstance(obj[k],dict):
                        self[k].merge( obj[k] )
                    else:
                        self[k] = [ self[k], obj[k] ]
                else:
                    if isinstance(obj[k],dict):
                        self[k] = Object( obj[k] )
                    else:
                        self[k] = obj[k]
        return self

def test01():
    class UObject( Object ):
        pass
    obj = Object({1:2})
    d = {}
    d.update({
        "a": 1,
        "b": {
            "c": 2,
            "d": [ 3, 4, 5 ],
            "e": [ [6,7], (8,9) ],
            "self": d,
        },
        1: 10,
        "1": 11,
        "obj": obj,
    })
    x = UObject(d)


    assert x.a == x["a"] == 1
    assert x.b.c == x["b"]["c"] == 2
    assert x.b.d[0] == 3
    assert x.b.d[1] == 4
    assert x.b.e[0][0] == 6
    assert x.b.e[1][0] == 8
    assert x[1] == 10
    assert x["1"] == 11
    assert x[1] != x["1"]
    assert id(x) == id(x.b.self.b.self) == id(x.b.self)
    assert x.b.self.a == x.b.self.b.self.a == 1

    x.x = 12
    assert x.x == x["x"] == 12
    x.y = {"a":13,"b":[14,15]}
    assert x.y.a == 13
    assert x.y.b[0] == 14

def test02():
    x = Object({
        "a": {
            "b": 1,
            "c": [ 2, 3 ]
        },
        1: 6,
        2: [ 8, 9 ],
        3: 11,
    })
    y = Object({
        "a": {
            "b": 4,
            "c": [ 5 ]
        },
        1: 7,
        2: 10,
        3: [ 12 , 13 ],
    })
    z = {
        3: 14,
        2: 15,
        "a": {
            "b": 16,
            "c": 17,
        }
    }
    x.merge( y, z )
    assert 2 in x.a.c
    assert 3 in x.a.c
    assert 5 in x.a.c
    assert 1 in x.a.b
    assert 4 in x.a.b
    assert 8 in x[2]
    assert 9 in x[2]
    assert 10 in x[2]
    assert 11 in x[3]
    assert 12 in x[3]
    assert 13 in x[3]
    assert 14 in x[3]
    assert 15 in x[2]
    assert 16 in x.a.b
    assert 17 in x.a.c

if __== '__main__':
    test01()
    test02()
4
truease.com

私はすでにここにたくさんの答えがあることを知っています、そして私はパーティーに遅刻します、しかしこのメソッドは再帰的にそしてその場で辞書をオブジェクトのような構造に変換します... 3.x.xの作品

def dictToObject(d):
    for k,v in d.items():
        if isinstance(v, dict):
            d[k] = dictToObject(v)
    return namedtuple('object', d.keys())(*d.values())

# Dictionary created from JSON file
d = {
    'primaryKey': 'id', 
    'metadata': 
        {
            'rows': 0, 
            'lastID': 0
        }, 
    'columns': 
        {
            'col2': {
                'dataType': 'string', 
                'name': 'addressLine1'
            }, 
            'col1': {
                'datatype': 'string', 
                'name': 'postcode'
            }, 
            'col3': {
                'dataType': 'string', 
                'name': 'addressLine2'
            }, 
            'col0': {
                'datatype': 'integer', 
                'name': 'id'
            }, 
            'col4': {
                'dataType': 'string', 
                'name': 'contactNumber'
            }
        }, 
        'secondaryKeys': {}
}

d1 = dictToObject(d)
d1.columns.col1 # == object(datatype='string', name='postcode')
d1.metadata.rows # == 0
4

空のオブジェクトの__dict__にあなたのdictを代入するだけですか?

class Object:
    """If your dict is "flat", this is a simple way to create an object from a dict

    >>> obj = Object()
    >>> obj.__dict__ = d
    >>> d.a
    1
    """
    pass

もちろん、辞書を再帰的に見て回らない限り、これはネストされた辞書の例では失敗します。

# For a nested dict, you need to recursively update __dict__
def dict2obj(d):
    """Convert a dict to an object

    >>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
    >>> obj = dict2obj(d)
    >>> obj.b.c
    2
    >>> obj.d
    ["hi", {'foo': "bar"}]
    """
    try:
        d = dict(d)
    except (TypeError, ValueError):
        return d
    obj = Object()
    for k, v in d.iteritems():
        obj.__dict__[k] = dict2obj(v)
    return obj

そしてあなたの例のリスト要素はおそらくMapping、このような(キー、値)のペアのリストであることを意味していました:

>>> d = {'a': 1, 'b': {'c': 2}, 'd': [("hi", {'foo': "bar"})]}
>>> obj = dict2obj(d)
>>> obj.d.hi.foo
"bar"
3
hobs

私はディクストのリストをオブジェクトのリストに再帰的に変換する必要がある場合に遭遇しました。そのため、Robertoのスニペットを基にしました。

def dict2obj(d):
    if isinstance(d, dict):
        n = {}
        for item in d:
            if isinstance(d[item], dict):
                n[item] = dict2obj(d[item])
            Elif isinstance(d[item], (list, Tuple)):
                n[item] = [dict2obj(elem) for elem in d[item]]
            else:
                n[item] = d[item]
        return type('obj_from_dict', (object,), n)
    Elif isinstance(d, (list, Tuple,)):
        l = []
        for item in d:
            l.append(dict2obj(item))
        return l
    else:
        return d

明白な理由で、どんなTupleも同等のリストに変換されることに注意してください。

あなたのすべての答えが私のためにしたのと同じくらい多くの人に役立つことを願っています。

3
NiKo
from mock import Mock
d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
my_data = Mock(**d)

# We got
# my_data.a == 1
3
forward

これもうまくいきます

class DObj(object):
    pass

dobj = Dobj()
dobj.__dict__ = {'a': 'aaa', 'b': 'bbb'}

print dobj.a
>>> aaa
print dobj.b
>>> bbb
3
naren

この小さなパラダイムの私のバージョンをアップロードしたいと思いました。

class Struct(dict):
  def __init__(self,data):
    for key, value in data.items():
      if isinstance(value, dict):
        setattr(self, key, Struct(value))
      else:   
        setattr(self, key, type(value).__init__(value))

      dict.__init__(self,data)

クラスにインポートされた型の属性は保持されます。私の唯一の関心事はあなたの構文解析の辞書の中からメソッドを上書きすることでしょう。それ以外はしっかりしているようです。

3
Erik

これはどう:

from functools import partial
d2o=partial(type, "d2o", ())

これは次のようになります。

>>> o=d2o({"a" : 5, "b" : 3})
>>> print o.a
5
>>> print o.b
3
2
onno

これは別の実装です。

class DictObj(object):
    def __init__(self, d):
        self.__dict__ = d

def dict_to_obj(d):
    if isinstance(d, (list, Tuple)): return map(dict_to_obj, d)
    Elif not isinstance(d, dict): return d
    return DictObj(dict((k, dict_to_obj(v)) for (k,v) in d.iteritems()))

[編集]他の辞書だけでなく、リスト内の辞書の扱いについても少し見逃していました。修正を追加しました。

2
Brian

これはSilentGhostの最初の提案を実装する別の方法です:

def dict2obj(d):
  if isinstance(d, dict):
    n = {}
    for item in d:
      if isinstance(d[item], dict):
        n[item] = dict2obj(d[item])
      Elif isinstance(d[item], (list, Tuple)):
        n[item] = [dict2obj(elem) for elem in d[item]]
      else:
        n[item] = d[item]
    return type('obj_from_dict', (object,), n)
  else:
    return d
2
rob

私は、辞書は数字、文字列、そして辞書で構成されていると思います。そのため、タプル、リスト、その他の型が辞書の最終的な次元に現れないという状況は無視します。

継承と再帰を考慮すると、印刷の問題を便利に解決し、データを照会する2つの方法、データを編集する1つの方法も提供します。

下の例を見てください。学生に関するいくつかの情報が書かれています。

group=["class1","class2","class3","class4",]
rank=["rank1","rank2","rank3","rank4","rank5",]
data=["name","sex","height","weight","score"]

#build a dict based on the lists above
student_dic=dict([(g,dict([(r,dict([(d,'') for d in data])) for r in rank ]))for g in group])

#this is the solution
class dic2class(dict):
    def __init__(self, dic):
        for key,val in dic.items():
            self.__dict__[key]=self[key]=dic2class(val) if isinstance(val,dict) else val


student_class=dic2class(student_dic)

#one way to edit:
student_class.class1.rank1['sex']='male'
student_class.class1.rank1['name']='Nan Xiang'

#two ways to query:
print student_class.class1.rank1
print student_class.class1['rank1']
print '-'*50
for rank in student_class.class1:
    print getattr(student_class.class1,rank)

結果:

{'score': '', 'sex': 'male', 'name': 'Nan Xiang', 'weight': '', 'height': ''}
{'score': '', 'sex': 'male', 'name': 'Nan Xiang', 'weight': '', 'height': ''}
--------------------------------------------------
{'score': '', 'sex': '', 'name': '', 'weight': '', 'height': ''}
{'score': '', 'sex': '', 'name': '', 'weight': '', 'height': ''}
{'score': '', 'sex': 'male', 'name': 'Nan Xiang', 'weight': '', 'height': ''}
{'score': '', 'sex': '', 'name': '', 'weight': '', 'height': ''}
{'score': '', 'sex': '', 'name': '', 'weight': '', 'height': ''}
2
tcpiper
class Struct(dict):
    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        self[name] = value

    def copy(self):
        return Struct(dict.copy(self))

使用法:

points = Struct(x=1, y=2)
# Changing
points['x'] = 2
points.y = 1
# Accessing
points['x'], points.x, points.get('x') # 2 2 2
points['y'], points.y, points.get('y') # 1 1 1
# Accessing inexistent keys/attrs 
points['z'] # KeyError: z
points.z # AttributeError: z
# Copying
points_copy = points.copy()
points.x = 2
points_copy.x # 1
1
Paulo Freitas

" python:クラスに動的にプロパティを追加するにはどうすればいいですか? ":

class data(object):
    def __init__(self,*args,**argd):
        self.__dict__.update(dict(*args,**argd))

def makedata(d):
    d2 = {}
    for n in d:
        d2[n] = trydata(d[n])
    return data(d2)

def trydata(o):
    if isinstance(o,dict):
        return makedata(o)
    Elif isinstance(o,list):
        return [trydata(i) for i in o]
    else:
        return o

変換したいディクショナリーに対してmakedataを呼び出すか、入力として何を期待しているかに応じてtrydataを呼び出すと、データオブジェクトが吐き出されます。

ノート:

  • もっと機能が必要な場合はtrydataにelifsを追加することができます。
  • x.a = {}などが必要な場合は、これは機能しません。
  • 読み取り専用のバージョンが必要な場合は、 元の回答 のクラスデータを使用してください。
1
David X

これはnamedtupleを使った入れ子の準備ができたバージョンです:

from collections import namedtuple

class Struct(object):
    def __new__(cls, data):
        if isinstance(data, dict):
            return namedtuple(
                'Struct', data.iterkeys()
            )(
                *(Struct(val) for val in data.values())
            )
        Elif isinstance(data, (Tuple, list, set, frozenset)):
            return type(data)(Struct(_) for _ in data)
        else:
            return data

=>

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> s = Struct(d)
>>> s.d
['hi', Struct(foo='bar')]
>>> s.d[0]
'hi'
>>> s.d[1].foo
'bar'
1
lajarre

この小さなクラスは私に何の問題も与えません。ただそれを拡張してcopy()メソッドを使うだけです。

  import simplejson as json

  class BlindCopy(object):

    def copy(self, json_str):
        dic = json.loads(json_str)
        for k, v in dic.iteritems():
            if hasattr(self, k):
                setattr(self, k, v);
0
thiago marini

私の辞書はこのフォーマットです:

addr_bk = {
    'person': [
        {'name': 'Andrew', 'id': 123, 'email': '[email protected]',
         'phone': [{'type': 2, 'number': '633311122'},
                   {'type': 0, 'number': '97788665'}]
        },
        {'name': 'Tom', 'id': 456,
         'phone': [{'type': 0, 'number': '91122334'}]}, 
        {'name': 'Jack', 'id': 7788, 'email': '[email protected]'}
    ]
}

見てわかるように、私は辞書のネスト辞書のリストを持っています。これは、addr_bkがlwpb.codecを使用してpython dictに変換したプロトコルバッファデータからデコードされたためです。オプションのフィールド(例:email =>キーが利用できない場合)と繰り返しのフィールド(例:phone =>辞書のリストに変換されたもの)があります。

私は上で提案した解決策をすべて試しました。入れ子になった辞書をうまく処理できない人もいます。他の人はオブジェクトの詳細を簡単に印刷できません。

Dawie Straussによるdict2obj(dict)の解決策だけが最も効果的です。

キーが見つからない場合の処理​​を少し強化しました。

# Work the best, with nested dictionaries & lists! :)
# Able to print out all items.
class dict2obj_new(dict):
    def __init__(self, dict_):
        super(dict2obj_new, self).__init__(dict_)
        for key in self:
            item = self[key]
            if isinstance(item, list):
                for idx, it in enumerate(item):
                    if isinstance(it, dict):
                        item[idx] = dict2obj_new(it)
            Elif isinstance(item, dict):
                self[key] = dict2obj_new(item)

    def __getattr__(self, key):
        # Enhanced to handle key not found.
        if self.has_key(key):
            return self[key]
        else:
            return None

それから、私はそれを使ってそれをテストしました:

# Testing...
ab = dict2obj_new(addr_bk)

for person in ab.person:
  print "Person ID:", person.id
  print "  Name:", person.name
  # Check if optional field is available before printing.
  if person.email:
    print "  E-mail address:", person.email

  # Check if optional field is available before printing.
  if person.phone:
    for phone_number in person.phone:
      if phone_number.type == codec.enums.PhoneType.MOBILE:
        print "  Mobile phone #:",
      Elif phone_number.type == codec.enums.PhoneType.HOME:
        print "  Home phone #:",
      else:
        print "  Work phone #:",
      print phone_number.number
0
Whospal

__getattr__が呼び出されないという問題がいくつかありましたので、新しいスタイルクラスのバージョンを作成しました。

class Struct(object):
    '''The recursive class for building and representing objects with.'''
    class NoneStruct(object):
        def __getattribute__(*args):
            return Struct.NoneStruct()

        def __eq__(self, obj):
            return obj == None

    def __init__(self, obj):
        for k, v in obj.iteritems():
            if isinstance(v, dict):
                setattr(self, k, Struct(v))
            else:
                setattr(self, k, v)

    def __getattribute__(*args):
        try:
            return object.__getattribute__(*args)
        except:            
            return Struct.NoneStruct()

    def __repr__(self):
        return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for 
(k, v) in self.__dict__.iteritems()))

このバージョンでは、属性が呼び出されたときに設定されていないNoneStructが追加されています。これにより、Noneテストで属性が存在するかどうかを確認できます。正確な辞書入力がわからない場合(設定など)に非常に便利です。

bla = Struct({'a':{'b':1}})
print(bla.a.b)
>> 1
print(bla.a.c == None)
>> True
0
RickyA

dictobjectに変換

from types import SimpleNamespace

def dict2obj(data):
    """将字典对象转换为可访问的对象属性"""
    if not isinstance(data, dict):
        raise ValueError('data must be dict object.')

    def _d2o(d):
        _d = {}
        for key, item in d.items():
            if isinstance(item, dict):
                _d[key] = _d2o(item)
            else:
                _d[key] = item
        return SimpleNamespace(**_d)

    return _d2o(data)

参考回答

0
David_li

これは、辞書のリストをオブジェクトに変換するもう1つの方法です。

def dict2object(in_dict):
    class Struct(object):
        def __init__(self, in_dict):
            for key, value in in_dict.items():
                if isinstance(value, (list, Tuple)):
                    setattr(
                        self, key,
                        [Struct(sub_dict) if isinstance(sub_dict, dict)
                         else sub_dict for sub_dict in value])
                else:
                    setattr(
                        self, key,
                        Struct(value) if isinstance(value, dict)
                        else value)
    return [Struct(sub_dict) for sub_dict in in_dict] \
        if isinstance(in_dict, list) else Struct(in_dict)
0