İç içe Python dict nesnesine dönüştürmek?


538

Bazı iç içe dicts ve listeleri (yani javascript tarzı nesne sözdizimi) ile bir dikte öznitelik erişimi kullanarak veri almak için zarif bir yol arıyorum.

Örneğin:

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

Bu şekilde erişilebilir olmalıdır:

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

Bence, bu özyineleme olmadan mümkün değil, ama dikte için bir nesne stili elde etmenin güzel bir yolu ne olurdu?


6
Son zamanlarda benzer bir şey yapmaya çalışıyordum, ancak yinelenen bir sözlük anahtarı ("from" - Python anahtar kelimesi) onunla geçmemi engelledi. Çünkü bu özelliğe erişmek için "x.from" kullanmayı denediğiniz anda bir sözdizimi hatası alırsınız.
Dawie Strauss

3
bu gerçekten bir sorun, ama büyük dikte yapılarına erişim hayat kolaylaştırmak için "from" terk edebilirsiniz :) x ['a'] ['d'] [1] ['foo'] yazmak gerçekten sinir bozucu, yani xad [1] .foo kuralları. gerekiyorsa, getattr (x, 'from') üzerinden erişebilir veya bunun yerine _from özelliğini kullanabilirsiniz.
Marc

5
from_PEP 8'e_from göre değil .
Kos

1
getattr(x, 'from')Özelliği yeniden adlandırmak yerine kullanabilirsiniz .
George V. Reilly

3
Bu "çözümler" çoğu (hatta kabul birinin iç içe izin vermez işe görünmüyor d1.b.c), ben size örneğin bir kütüphaneden bir şey kullanıyor olmalıdır temizlemek olduğunu düşünüyorum koleksiyonlardan namedtuple olarak, bu yanıt , anlaşılacağı .. .
Andy Hayden

Yanıtlar:


660

Güncelleme: Python 2.6 ve sonrasında, namedtupleveri yapısının ihtiyaçlarınıza uygun olup olmadığını göz önünde bulundurun :

>>> 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']

Alternatif (orijinal cevap içeriği):

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

Ardından şunları kullanabilirsiniz:

>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2

19
Burada da aynı - bu özellikle Python nesnelerini MongoDB gibi belgeye yönelik veritabanlarından yeniden oluşturmak için kullanışlıdır.
mikemaccana

13
Daha güzel baskı almak için şunu ekleyin: def repr __ (self): (k, v için '<% s>'% str ('\ n' .join ('% s:% s'% (k, repr (v)) 'i döndürün ) in self .__ dict .iteritems ()))
altı8

15
Bu iç içe sözlüklerle çalışır mı? ve nesne ve / veya liste vb içeren içeren dikte. Herhangi bir yakalama var mı?
Sam Stoelinga

5
@Sam S: İç Structiçe sözlüklerden iç içe geçmiş s oluşturmaz , ancak genel olarak değerin türü herhangi bir şey olabilir. Anahtar, bir nesne yuvası için uygun olmakla sınırlıdır
Eli Bendersky

51
-1 o) iç içe soru açıkça istedi dicts, ve b değil çalışır aynı işlevi şu standart kütüphanelerde mevcut) bir nedeni argparse.Namespacede tanımlamıştır ( __eq__, __ne__, __contains__).
wim

110
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'

7
İyi! Ancak, daha küçük bir bellek alanı için .items () yerine .iteritems () ile değiştirilir.
Eric O Lebigot

7
Bir OP gereksinimi değilse, bu bir sorun değildir - ancak bunun listelerdeki listelerde nesneleri tekrar tekrar işlemeyeceğini unutmayın.
Anon

3
Bunun eski bir cevap olduğunun farkındayım, ama bu günlerde bu çirkin çizgi yerine soyut bir temel sınıf kullanmak daha iyi olurduif isinstance(b, (list, tuple)):
wim

4
İpucu: Okunabilir dize gösterimi gibi ek özellikler için objsınıfın devralmasını sağlayın argparse.Namespace.
Serrano

2
Kullanım durumuna bağlı olarak, genellikle bunun olup olmadığını kontrol ediyorum değil bir dize türü ama bu olduğu bir Dizi türü
wim

108

Şaşırtıcı bir kimse söz vardır Demet . Bu kütüphane yalnızca dikte nesnelerine nitelik stili erişimi sağlamak için tasarlanmıştır ve OP'nin tam olarak ne istediğini yapar. Bir gösteri:

>>> 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'

Bir Python 3 kütüphanesi şu adreste bulunabilir: https://github.com/Infinidat/munch - Kredi codyzu'ya gidiyor


16
Ve Munch adlı Bunch'un uyumlu bir python 3 uyumlu (2.6-3.4 gibi) şubesi var: github.com/Infinidat/munch
codyzu 28:14

Demet, bunların çoğunun en iyi çözümüdür, çünkü çoklu serileştirme tiplerini iyi destekler ve korunur. Harika teşekkür ederim. Keşke python3 sürümü aynı şey olarak isimlendirildi, çünkü neden olmasın.
Jonathan

4
Yani bu konuda sadece bir önsöz, Bunch ve Attrdict çok yavaş. Bizim uygulamada sık kullanım gördüklerinde onlar benim istek süresinin yaklaşık 1/3 ve 1/2 tüketti. Kesinlikle görmezden gelinecek bir şey değil. Bunun hakkında daha fazla konuşun stackoverflow.com/a/31569634/364604 .
JayD3e

Bu, diktelere nesne benzeri erişime izin verirken, bunu getattr aracılığıyla yapar . Bu, IPython gibi akıllı REPL'lerde içgözlemi zorlaştırır.
GDorn


64
x = type('new_dict', (object,), d)

sonra buna özyineleme ekleyin ve işiniz bitti.

düzenlemek bu bunu uygulamak şey mi:

>>> 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'

1
Neden tip nesneleri yaratıyorsunuz ve somutlaştırmıyorsunuz? Bu daha mantıklı olmaz mıydı? Yani, neden top_instance = top()geri dönmüyorsun ve geri döndüğün yere geri dönüyorsun top?
gözleme

6
"Yaprak" verileri için güzel, ancak örnekler rahatça "çırpı" gibi xve x.bhangi çirkin geri <class '__main__.new'>
bırakır

46

Bunu namedtuplesizin için yapabilen bir koleksiyon yardımcısı var:

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

28
Bu, iç içe dikler için özyineleme sorununa cevap vermez.
türetilebilir

4
adlandırılmış başlıkları değiştiremezsiniz.
Max

() Ve değerleri () ile döndürülen liste sırasının sırayla eşleştiğini garanti edebilir miyiz? Demek istediğim, eğer bu bir OrdereredDict ise, evet. Ama standart bir karar mı? CPython 3.6+ ve PyPy "kompakt" dikterin sipariş edildiğini, ancak belgelere dikkat çektiğini biliyorum: "Bu yeni uygulamanın siparişi koruyan yönü bir uygulama detayı olarak kabul edildi ve buna güvenilmemeli"
Havok

38
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

Herhangi bir derinliğin herhangi bir sekans / dikte / değer yapısı ile kullanılabilir.


4
Cevap bu olmalı. Yuvalamak için iyi çalışır. Bunu json.load () için bir object_hook olarak da kullanabilirsiniz.
010110110101

2
SilentGhost'un 2009'daki işlevsel cevabına benzer şekilde - yaprak düğümü verilerine erişilebilir, ancak üst / dallar nesne referansları olarak görüntülenir. Güzel yazdırmak için,def __repr__(self): return '{%s}' % str(', '.join("'%s': %s" % (k, repr(v)) for (k, v) in self.__dict__.iteritems()))
MarkHu

5
Python 3.x kullanıcıları: sadece satır 4 .items()yerine. .iteritems()(İşlev yeniden adlandırıldı, ancak esasen aynıdır )
neo post modern

Yuvalanmış nesneler için mükemmel çalışır, teşekkürler! Python3 iteritems için I, () gibi bir açıklama yenilere () öğelere değiştirilmelidir gibi
Óscar Andreu

31

Hissettiğimi almak, önceki örneklerin en iyi yönleri.

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()))

Yapıcı kısaltılabilir: def __init__(self, dct): for k, v in dct.iteritems(): setattr(self, k, isinstance(v, dict) and self.__class__(v) or v) Bu daStruct
George V. Reilly

2
Kendi cevabımı küçümsemeyi tercih ederim, ama buna geri baktığımda, bunun dizi türlerine geri çekilmediğini fark ettim. xd [1] .foo bu durumda başarısız olur.
andyvanee

2
isinstance(v, dict)çek daha iyi olarak olurdu isinstance(v, collections.Mapping)o şeylerin dict benzeri geleceği işleyebilir böylece
ocak

29

Eğer dikteniz geliyorsa json.loads(), bunu tek bir satırda (dikt yerine) bir nesneye dönüştürebilirsiniz:

import json
from collections import namedtuple

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

Ayrıca bkz. JSON verilerini bir Python nesnesine dönüştürme .


.loadsBüyük bir JSON nesneniz varsa normalden çok daha yavaş görünüyor
michaelsnowden

16

Dikte tuşlarına bir nesne olarak (veya zor tuşlar için bir diksiyon olarak) erişmek istiyorsanız, yinelemeli olarak yapın ve orijinal dikseli güncelleyebilmeniz için şunları yapabilirsiniz:

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)

Örnek kullanım:

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'}}

13
>>> 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'

12

Ben İKİ çalışırken sona erdi AttrDict ve Bunchkütüphaneleri kullandım ve kullanımlarım için çok yavaş buldular. Bir arkadaşım ve ben içine baktıktan sonra, bu kütüphaneleri yazmanın ana yönteminin kütüphanede, iç içe geçmiş bir nesneyi agresif bir şekilde yinelediğini ve sözlük nesnesinin kopyalarını oluşturduğunu gördük. Bunu aklımızda tutarak, iki önemli değişiklik yaptık. 1) Tembel yüklenen öznitelikleri yaptık 2) sözlük nesnesinin kopyalarını oluşturmak yerine, hafif bir proxy nesnesinin kopyalarını yaratırız. Bu son uygulama. Bu kodu kullanmanın performans artışı inanılmaz. AttrDict veya Bunch kullanırken, bu iki kütüphane tek başına istek süremin 1/2 ve 1 / 3'ünü tüketiyordu (ne !?). Bu kod o zamanı neredeyse hiçbir şeye indirgemiştir (0.5ms aralığında bir yerde). Bu elbette ihtiyaçlarınıza bağlıdır,

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

Orijinal uygulanmasını bakın burada tarafından https://stackoverflow.com/users/704327/michael-merickel .

Dikkat edilmesi gereken diğer bir şey, bu uygulamanın oldukça basit olması ve ihtiyacınız olabilecek tüm yöntemleri uygulamamasıdır. Bunları DictProxy veya ListProxy nesnelerine gerektiği gibi yazmanız gerekir.


9

x.__dict__.update(d) iyi yapmalı.


Cevabınız için teşekkürler, ama x nedir? ya da standart bir nesne? bana bir ipucu verebilir misin lütfen.
Marc

x sizin nesnenizdir. Her nesnenin bir zorluğu vardır . Bir nesnenin sözünü güncelleyerek, aslında anahtarın değerini değiştirirsiniz.
Alex Rodrigues

Cesur sözler _ _ dict _ _
Alex Rodrigues

15
Bu, iç içe sözlükleri işlemez.
FogleBird

Her nesnenin şunları __dict__object().__dict__AttributeError: 'object' object has no attribute '__dict__'
Will Manley

8

Özel bir nesne kancasıyla standart kitaplığın jsonmodülünden yararlanabilirsiniz :

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)

Örnek kullanım:

>>> 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'

Ve edilir kesinlikle salt okunur değil onunla olduğu gibi namedtuple, değerleri değiştirebilir - yani değil yapısı:

>>> o.b.c = 3
>>> o.b.c
3

1
Şimdiye kadarki en iyi cevap
Connor

Yuvalanmış elemanlar için json yükleme mekanizmasını kullanma fikrini seviyorum. Ama zaten bir kararımız var ve birinin bir nesneye eşlemek için ondan bir dize yaratması gerektiğinden hoşlanmıyorum. Nesneleri doğrudan bir diksiyondan yaratan bir çözüme sahip olmayı tercih ederim.
Sandro

1
İlk olarak dizeye dönüştürmek gerekiyor, ancak bir json.JSONEncoderve aracılığıyla genişletebildiğinden oldukça genel object_hook.
Sandro

6

Bu başlamanız gerekir:

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

Henüz listelerde çalışmaz. Listeleri bir UserList'e __getitem__sarmanız ve dikleri sarmak için aşırı yüklemeniz gerekir.


2
Listelerde çalışmasını sağlamak için, cevabın if isinstance(d, list)maddesini kullanın Anon.
Vinay Sajip

6

Zaten burada çok fazla cevap olduğunu biliyorum ve partiye geç kaldım ama bu yöntem özyinelemeli ve 'yerinde' bir sözlüğü nesne benzeri bir yapıya dönüştürecek ... 3.xx içinde çalışır

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

Ne demek "nesne benzeri yapı"?
MoralCode

1
Ördek yazma prensibi nedeniyle nesne benzeri. Demek istediğim, bir sınıf örneği olsaydı kendi özelliklerine erişebiliyorsunuz. ama bu anlamda bir nesne DEĞİL, adlandırılmış bir grup.
Aidan Haddon-Wright

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

# We got
# my_data.a == 1

4

Neredeyse bir süre önce kullandığım bir çözümü açıklayayım . Ama önce, yapmamamın nedeni, aşağıdaki kodun gerçeği ile gösterilmiştir:

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

print x.from

bu hatayı veriyor:

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

"Gönderen" bir Python anahtar kelimesi olduğundan, izin veremeyeceğiniz belirli sözlük anahtarları vardır.


Şimdi benim çözümüm, sözlük öğelerine isimlerini doğrudan kullanarak erişime izin veriyor. Ama aynı zamanda "sözlük anlambilimi" kullanmanıza izin verir. Örnek kullanım kodu:

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"

1
sınıf Yapı: def init __ (self, ** girişler): self .__ dict .update (girişler)
Kenneth Reitz

4

Eski Soru-Cevap, ama konuşacak daha çok şey var. Kimse özyinelemeli diksiyon hakkında konuşmuyor gibi görünüyor. Bu benim kodum:

#!/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 __name__ == '__main__':
    test01()
    test02()

4

Bu küçük paradigmanın versiyonumu yüklemek istedim.

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)

Sınıfa içe aktarılan türün niteliklerini korur. Benim tek endişem, ayrıştırma sözlük içindeki yöntemleri üzerine yazma olacaktır. Ama aksi halde sağlam görünüyor!


Her ne kadar güzel bir fikir olsa da, bu OP örneği için işe yaramıyor gibi görünüyor, aslında sözlükte geçirilen değişiklik gibi görünüyor! Aslında df.aişe yaramıyor bile.
Andy Hayden

4

Bu da iyi çalışıyor

class DObj(object):
    pass

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

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

3

İşte SilentGhost'un orijinal önerisini uygulamanın başka bir yolu:

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

3

Ben özetler listesini özyineli olarak nesneleri listesine dönüştürmek için gereken davayı tökezledi, bu yüzden Roberto'nun snippetine dayanarak benim için ne yaptı:

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

Herhangi bir grubun bariz nedenlerle liste eşdeğerine dönüştürüleceğini unutmayın.

Umarım bu cevapların benim için yaptığı kadar birine yardımcı olur beyler.


3

Ne yaklaşık Tıpkı atama dictiçin __dict__boş bir nesnenin?

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

Elbette bu, tekrar tekrar dikte yürümediğiniz sürece iç içe geçmiş örneğinizde başarısız olur:

# 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

Ve örnek liste öğeniz muhtemelen bir Mapping, (anahtar, değer) çiftlerinin bir listesi olması gerekiyordu :

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

2

İşte başka bir uygulama:

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()))

[Düzenle] Ayrıca sadece diğer dikte değil, listeler içinde dikte işlemek hakkında cevapsız bit. Düzeltme eklendi.


Kaynak sözlüğe diksenin ayarlanmasının , sonuçta ortaya çıkan nesne üzerindeki niteliklerde yapılacak herhangi bir değişikliğin, nesneyi oluşturan sözlüğü de etkileyeceği anlamına geldiğini unutmayın. Sözlük nesneyi oluşturmaktan başka bir şey için kullanılırsa, bu beklenmedik sonuçlara yol açabilir.
Mark Roddy

@Mark: Aslında, aynı dikte nesnesinden geçmek yerine her seferinde DictObj'e yeni bir sözlük geçiriliyor, bu aslında gerçekleşmeyecek. Bir sözlük içindeki değerleri de çevirmem gerektiğinden bunu yapmak zorunludur, bu yüzden orijinal dict nesnesini mutasyona uğratmadan geçmek imkansız olacaktır.
Brian

Buna çok az cevap var, kabul edilen cevap tekrarlayan ya da listeleri işleyecek gibi görünmüyordu. Hepsini okudum ve bu ilk bakışta en basit görünüyordu, test ettim ve işe yaradı. Mükemmel cevap.
AlwaysTraining

2
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))

Kullanımı:

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

2

Buna ne dersin:

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

Bu daha sonra şu şekilde kullanılabilir:

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

2

Bir diksiyon sayı, dize ve diksiyondan oluşan çoğu zaman yeterli olduğunu düşünüyorum. Bu yüzden, bir diksiyonun son boyutunda görünmeyen tuples, listeler ve diğer türlerin durumunu görmezden geliyorum.

Kalıtım göz önüne alındığında, özyineleme ile birlikte, yazdırma sorununu rahatça çözer ve ayrıca bir veriyi sorgulamak için iki yol sağlar, bir veri düzenlemenin bir yolu.

Öğrenciler hakkındaki bazı bilgileri açıklayan bir dikte olan aşağıdaki örneğe bakın:

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)

Sonuçlar:

{'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

Genellikle, dikte hiyerarşisini nesnenize yansıtmak istersiniz, ancak genellikle en düşük düzeydeki liste veya tuplleri yansıtmazsınız. İşte ben böyle yaptım:

class defDictToObject(object):

    def __init__(self, myDict):
        for key, value in myDict.items():
            if type(value) == dict:
                setattr(self, key, defDictToObject(value))
            else:
                setattr(self, key, value)

Yani yapıyoruz:

myDict = { 'a': 1,
           'b': { 
              'b1': {'x': 1,
                    'y': 2} },
           'c': ['hi', 'bar'] 
         }

ve Al:

x.b.b1.x 1

x.c ['merhaba', 'bar']


1

Sözlüğüm şu biçimde:

addr_bk = {
    'person': [
        {'name': 'Andrew', 'id': 123, 'email': 'andrew@mailserver.com',
         'phone': [{'type': 2, 'number': '633311122'},
                   {'type': 0, 'number': '97788665'}]
        },
        {'name': 'Tom', 'id': 456,
         'phone': [{'type': 0, 'number': '91122334'}]}, 
        {'name': 'Jack', 'id': 7788, 'email': 'jack@gmail.com'}
    ]
}

Görüldüğü gibi, sözlükleri ve dikte listesini iç içe geçirdim . Bunun nedeni, addr_bk'nin lwpb.codec kullanılarak bir python diksiyonuna dönüştürülen protokol arabellek verilerinden çözülmesidir. İsteğe bağlı alan (ör. Anahtarın kullanılamayabileceği e-posta =>) ve tekrarlanan alan (ör. Telefon => dikte listesine dönüştürülmüş) vardır.

Yukarıda önerilen tüm çözümleri denedim. Bazıları iç içe sözlükleri iyi işlemez. Diğerleri nesne ayrıntılarını kolayca yazdıramaz.

Sadece çözüm, Dawie Strauss'un dict2obj (dict) çözümü en iyi sonucu verir.

Anahtar bulunamadığında işlemek için biraz geliştirdim:

# 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

Sonra, ile test ettim:

# 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

1

" Python: Bir sınıfa dinamik olarak nasıl özellik eklenir? "

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

makedataDönüştürmek istediğiniz sözlüğü çağırırsınız ya da trydatagiriş olarak beklediğiniz şeye bağlı olarak bir veri nesnesi çıkarır.

Notlar:

  • Daha trydatafazla işlevselliğe ihtiyacınız varsa elif'ler ekleyebilirsiniz .
  • Açıkçası bu x.a = {}ya da benzeri istiyorsanız işe yaramaz .
  • Salt okunur bir sürüm istiyorsanız , orijinal yanıttaki sınıf verilerini kullanın .
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.