Bir nokta “.” Nasıl kullanılır Sözlük üyelerine erişmek için


283

Python sözlük üyelerini nokta "." Üzerinden nasıl erişilebilir yapabilirim?

Mesela yazmak yerine mydict['val']yazmak istiyorum mydict.val.

Ayrıca iç içe dikmelere bu şekilde erişmek istiyorum. Örneğin

mydict.mydict2.val 

atıfta bulunur

mydict = { 'mydict2': { 'val': ... } }

20
İnsanların iç içe dikleri kullandığı durumların birçoğu, yerine tuplesli dikteler tarafından d[a][b][c]değiştirilir d[a, b, c].
Mike Graham

7
Sihir değil: foo = {}; foo [1,2,3] = "bir, iki, üç!"; foo.keys () => [(1,2,3)]
Bryan Oakley

10
Vay. Vay canına tekrar. Tuples'in diktenin anahtarları olabileceğini bilmiyordum. Vay be üçüncü kez.
bodacydo

3
"Yıkanabilir" herhangi bir nesne, bir diktenin anahtarı olarak kullanılabilir. Çoğu değişmez nesne de yıkanabilir, ancak yalnızca tüm içerikleri yıkanabilirse. D [1, 2, 3] kodu çalışır, çünkü "," "bir grup operatörü oluştur"; d ile aynıdır [(1, 2, 3)]. Parantezler genellikle bir demetin bildirimi etrafında isteğe bağlıdır.
Larry Hastings

6
Anahtarın kendi başına bir nokta olduğu durumu düşündünüz mü {"my.key":"value"}? Ya da anahtar "from" gibi bir anahtar kelime olduğunda? Bunu birkaç kez düşündüm ve algılanan faydalardan daha fazla sorun ve sorun giderme.
Todor Minakov

Yanıtlar:


147

Yeni yaptığım bu sınıfı kullanarak yapabilirsiniz. Bu sınıfla Mapnesneyi başka bir sözlük gibi kullanabilirsiniz (json serileştirmesi dahil) veya nokta gösterimi ile. Size yardımcı olmayı umuyorum:

class Map(dict):
    """
    Example:
    m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
    """
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self[k] = v

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

Kullanım örnekleri:

m = Map({'first_name': 'Eduardo'}, last_name='Pool', age=24, sports=['Soccer'])
# Add new key
m.new_key = 'Hello world!'
# Or
m['new_key'] = 'Hello world!'
print m.new_key
print m['new_key']
# Update values
m.new_key = 'Yay!'
# Or
m['new_key'] = 'Yay!'
# Delete key
del m.new_key
# Or
del m['new_key']

21
Güncellenmiş Python 3 I çalışmalarına .iteritems()göre.items()
berto

13
Bunun, ortak özelliklerden farklı davranacağını, bu AttributeErrorözellik mevcut olmadığında artmayacağını unutmayın. Bunun yerine geri dönecektir None.
mic_e

Derin kopya ve diğer sistemlerin destekleyebilmesi için getstate ve setstate eklemeyi önerin .
user1363990

4
Oluşturucunuzu basitleştirebilirsiniz self.update(*args,**kwargs). Ayrıca ekleyebilirsiniz __missing__(self,key): value=self[key]= type(self)(); return value. Ardından nokta gösterimini kullanarak eksik girişler ekleyebilirsiniz. Seçilebilir olmasını istiyorsanız, ekleyebilirsiniz __getstate__ve__setstate__
Jens Munk

1
Bu hasattr(Map, 'anystring') is true. which means the hasattr would always return True due to overriding __getattr__` yapar
Xiao

265

Bunu her zaman bir util dosyasında sakladım. Kendi sınıflarınızda da bir karışım olarak kullanabilirsiniz.

class dotdict(dict):
    """dot.notation access to dictionary attributes"""
    __getattr__ = dict.get
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

mydict = {'val':'it works'}
nested_dict = {'val':'nested works too'}
mydict = dotdict(mydict)
mydict.val
# 'it works'

mydict.nested = dotdict(nested_dict)
mydict.nested.val
# 'nested works too'

5
Çok basit bir cevap, harika! IPython'da sekme tamamlama yapabilmek için ne yapmam gerektiğini biliyor musunuz? Sınıfın __dir __ (self) öğesini uygulaması gerekirdi, ama bir şekilde işe yarayamam.
andreas-h

8
Basitlik için +1. ama iç içe dikte üzerinde çalışmıyor gibi görünüyor. d = {'foo': {'bar': 'baz'}}; d = dotdict(d); d.foo.barbir öznitelik hatası atar, ancak d.fooiyi çalışır.
tmthyjames

2
Evet, bu karmaşık iç içe yapılar için çalışmaz.
David

16
@tmthyjames gibi nokta gösterimi ile özniteliklere özyinelemeli olarak erişmek için getter yönteminde dotdict türü nesneyi döndürebilirsiniz:python class DotDict(dict): """dot.notation access to dictionary attributes""" def __getattr__(*args): val = dict.get(*args) return DotDict(val) if type(val) is dict else val __setattr__ = dict.__setitem__ __delattr__ = dict.__delitem__
TMKasun

4
Bunu denedikten sonra, eksik öğeler için bir hata oluşturmak yerine getgeri döneceğinden, gerçekten kötü bir fikir gibi görünüyor None...
NichtJens

117

dotmapÜzerinden yüklepip

pip install dotmap

Yapmasını istediğiniz her şeyi ve alt sınıfları yapar dict, bu yüzden normal bir sözlük gibi çalışır:

from dotmap import DotMap

m = DotMap()
m.hello = 'world'
m.hello
m.hello += '!'
# m.hello and m['hello'] now both return 'world!'
m.val = 5
m.val2 = 'Sam'

Bunun da ötesinde, dict nesnelere nesnelerden :

d = m.toDict()
m = DotMap(d) # automatic conversion in constructor

Bu, erişmek istediğiniz bir şey zaten mevcutsa dict formdaysa, DotMapkolay erişim için bunu bir haline dönüştürebileceğiniz :

import json
jsonDict = json.loads(text)
data = DotMap(jsonDict)
print data.location.city

Son olarak, otomatik olarak yeni çocuk oluşturur DotMap örnekleri böylece böyle şeyler yapabilirsiniz:

m = DotMap()
m.people.steve.age = 31

Bunch ile Karşılaştırma

Tam açıklama: Ben DotMap'in yaratıcısıyım . Ben yarattım çünküBunch bu özellikler eksikti

  • sipariş öğelerinin hatırlanması ve bu sırayla yinelenmesi
  • otomatik çocuk DotMapçok fazla hiyerarşiniz olduğunda zaman kazandıran ve daha temiz kodlar sağlayan oluşturma
  • dicttüm çocuk dictörneklerinden bir ve özyinelemeli olarakDotMap

2
:-) adında zaten nokta olan tuşlarla çalışmasını sağlayabilir misiniz? {"test.foo": "bar"}üzerinden ulaşılabilir mymap.test.fooBu harika olurdu. Düz bir haritayı derin bir haritaya dönüştürmek ve sonra DotMap uygulamak biraz gerileme alacaktır, ancak buna değer!
dlite922

Temiz. Sekme listelemenin / tamamlamanın Jupyter dizüstü bilgisayarındaki tuşlarla çalışmasını sağlamanın bir yolu var mı? Nokta tarzı erişim, etkileşimli kullanım için en değerlidir.
Dmitri

@ Dmitri Cool ürünü. Daha önce hiç duymadım, bu yüzden otomatik tamamlamanın nasıl çalışacağından emin değilim. DotMapOtomatik tamamlama ile kullanmayı en iyi şekilde kabul ediyorum . Önceden yazılan anahtar kelimeleri otomatik olarak tamamlayan Yüce Metin kullanıyorum.
Chris Redford

1
**kwargsVeya gibi şeyler için sözlük çıkarma eksik olduğunu düşünüyorum c = {**a, **b}. Aslında, sessizce başarısız olur, ayıklanırken boş bir sözlük gibi davranır.
Simon Streicher

@SimonStreicher Bunu test m = DotMap(); m.a = 2; m.b = 3; print('{a} {b}'.format(**m));ettim ve beklenenleri aldım 2 3. İşe yarayan dict()ancak çalışmayan, kanıtlanmış bir bozuk vakanız varsa DotMap(), lütfen kodunuzu GitHub'daki Sorunlar sekmesine gönderin.
Chris Redford

56

Dikteden türetmek ve uygulamak __getattr__ve__setattr__ .

Veya Bunch'u kullanabilirsiniz çok benzer olan .

Yerleşik dikt sınıfını maymunbalığı yapmanın mümkün olduğunu sanmıyorum.


2
Monkeypatch tam olarak ne anlama geliyor? Bunu duydum ama kullanmadım. (Bu tür yeni başlayanlar için sorular sorduğum için üzgünüm, henüz programlama konusunda iyi değilim (ben sadece 2. sınıf öğrencisiyim.))
bodacydo

9
Monkeypatching, genellikle kaynak kodunda tanımlanacak bir şeyi değiştirmek için Python'un (veya herhangi bir dilin) ​​dinamikliğini kullanıyor. Özellikle oluşturulduktan sonra sınıfların tanımını değiştirmek için geçerlidir.
Mike Graham

Bu işlevi çok kullanıyorsanız Bunch'ın hızına dikkat edin. Oldukça sık kullanıyordum ve istek süremin üçte birini tüketiyordu. Bunun daha ayrıntılı bir açıklaması için cevabımı kontrol et.
JayD3e

22

Kumaşın gerçekten güzel ve minimal bir uygulaması var . İç içe erişime izin vermek için bunu genişleterek, a kullanabiliriz defaultdictve sonuç şöyle görünür:

from collections import defaultdict

class AttributeDict(defaultdict):
    def __init__(self):
        super(AttributeDict, self).__init__(AttributeDict)

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

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

Aşağıdaki gibi kullanın:

keys = AttributeDict()
keys.abc.xyz.x = 123
keys.abc.xyz.a.b.c = 234

Bu, Kugel'in "Diksiyondan ve uygulamadan __getattr__ve __setattr__" den verdiği cevabı biraz detaylandırıyor . Şimdi nasıl olduğunu biliyorsun!


1
Bu harika!
Thomas Klinger

Bir defaultdict eklemek güzel - ancak bu sadece bir dikteyi sıfırdan başlatırken işe yarıyor gibi görünüyor. Mevcut bir dikdörtgeni özyineli olarak bir "dotdict" e dönüştürmemiz gerekiyorsa. İşte dotdictmevcut dictnesneyi özyineli olarak dönüştürmeye izin veren bir alternatif : gist.github.com/miku/…
miku

19

Bunu denedim:

class dotdict(dict):
    def __getattr__(self, name):
        return self[name]

deneyebilirsin __getattribute__ .

Her dikteyi bir tür dotdict yeterince iyi yapar, eğer bunu çok katmanlı bir diksiyondan başlatmak istiyorsanız, uygulamayı __init__da deneyin .


Üzgünüz, @Kugel 'in cevabı benzer.
tdihp

1
tdihp, cevabınızı hala seviyorum çünkü daha hızlı anladım - gerçek kodu var.
yigal

1
Gerçek kod için +1. Ancak @ Kugel'in Bunch kullanma önerisi de çok iyi.
Dannid

Bunu def docdict(name):daha önce yerleştirerek ve sonra `` isinstance (name, dict) '' ile bir fonksiyonun içine yerleştirmeyi yararlı buldum : return DotDict (name) return name `
Daniel Moskovich

Büyük basit bir örnek .. bu biraz iç içe bir dict kolayca @DanielMoskovich benzer zincirleme şekilde biraz genişletilmiş, ancak bulunamadı eğer ayrıca int, string, vb ... ya null doğru yaprak düğümleri döndürürclass dotdict(dict): def __getattr__(self, name): if name not in self: return None elif type(self[name]) is dict: return JsonDot(self[name]) else: return self[name]
D Sievers

11

Yapma. Öznitelik erişimi ve dizine ekleme, Python'daki ayrı şeylerdir ve bunların aynı şekilde yapılmasını istememelisiniz. namedtupleErişilebilir özniteliklere sahip olması gereken bir şey varsa bir sınıf (muhtemelen tarafından yapılan ) yapın ve []bir diksiyondan bir öğe almak için gösterimi kullanın.


Cevap için teşekkürler. Ancak ben de sorduğum şu soruya bir göz atın: stackoverflow.com/questions/2352252/… Mako şablonlarındaki karmaşık veri yapılarına erişmek .yerine kullanmak için iyi bir fikir gibi görünüyor [].
bodacydo

2
Bunun için bir kullanım durumu görebiliyorum; aslında, sadece birkaç hafta önce yaptım. Benim durumumda nokta gösterimiyle özniteliklere erişebileceğim bir nesne istedim. Tüm dict özelliklerini yerleşik olarak almak için basitçe dict'den miras almayı çok kolay buldum, ancak bu nesneye genel arabirim nokta gösterimini kullanıyor (aslında bazı statik verilere salt okunur bir arayüz). Kullanıcılarım 'foo.bar' ile 'foo ["bar"]' ile olduğundan çok daha mutlular ve sözlü veri tipinin özelliklerini geri çekebildiğim için mutluyum.
Bryan Oakley

10
Zaten iyi Python stilini biliyorsunuz: Size söylüyoruz, bir diktenin değerlerinin niteliklermiş gibi davranmayın. Kötü uygulama. Örneğin, "öğeler" veya "get" veya "pop" gibi bir diktenin mevcut özelliğiyle aynı ada sahip bir değer depolamak isterseniz ne olur? Muhtemelen kafa karıştırıcı bir şey. Öyleyse yapma!
Larry Hastings

5
Hata! 'Öğeler', 'al' veya 'pop' gibi özellikleri unuttum. Bu önemli örneği getirdiğin için teşekkürler!
bodacydo

5
@Gabe, uzun zaman oldu ... ama sanırım söylemeye değer. "JS'de yeterince iyi" değil: "JS'de yeterince korkunç". Prototip zincirindeki diğer önemli özelliklerle aynı ada sahip anahtarlar / attr depoladığınızda komik olur.
bgusach

11

Değiştirilmiş sözlüğünüzü seçmek istiyorsanız, yukarıdaki yanıtlara birkaç durum yöntemi eklemeniz gerekir:

class DotDict(dict):
    """dot.notation access to dictionary attributes"""
    def __getattr__(self, attr):
        return self.get(attr)
    __setattr__= dict.__setitem__
    __delattr__= dict.__delitem__

    def __getstate__(self):
        return self

    def __setstate__(self, state):
        self.update(state)
        self.__dict__ = self

Turşu ile ilgili yorum için teşekkürler. Bu hatadan çıldırdım ve bunun sadece bu sorundan kaynaklandığını fark ettim!
Shagru

Copy.deepcopy kullandığınızda da olur. Bu ilave gerekli.
user1363990

Sadeleştirme:__getattr__ = dict.get
martineau

9

Kugel'in cevabına dayanarak ve Mike Graham'ın dikkatli sözlerini dikkate alarak, ya bir ambalaj yaparsak?

class DictWrap(object):
  """ Wrap an existing dict, or create a new one, and access with either dot 
    notation or key lookup.

    The attribute _data is reserved and stores the underlying dictionary.
    When using the += operator with create=True, the empty nested dict is 
    replaced with the operand, effectively creating a default dictionary
    of mixed types.

    args:
      d({}): Existing dict to wrap, an empty dict is created by default
      create(True): Create an empty, nested dict instead of raising a KeyError

    example:
      >>>dw = DictWrap({'pp':3})
      >>>dw.a.b += 2
      >>>dw.a.b += 2
      >>>dw.a['c'] += 'Hello'
      >>>dw.a['c'] += ' World'
      >>>dw.a.d
      >>>print dw._data
      {'a': {'c': 'Hello World', 'b': 4, 'd': {}}, 'pp': 3}

  """

  def __init__(self, d=None, create=True):
    if d is None:
      d = {}
    supr = super(DictWrap, self)  
    supr.__setattr__('_data', d)
    supr.__setattr__('__create', create)

  def __getattr__(self, name):
    try:
      value = self._data[name]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[name] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

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

  def __getitem__(self, key):
    try:
      value = self._data[key]
    except KeyError:
      if not super(DictWrap, self).__getattribute__('__create'):
        raise
      value = {}
      self._data[key] = value

    if hasattr(value, 'items'):
      create = super(DictWrap, self).__getattribute__('__create')
      return DictWrap(value, create)
    return value

  def __setitem__(self, key, value):
    self._data[key] = value

  def __iadd__(self, other):
    if self._data:
      raise TypeError("A Nested dict will only be replaced if it's empty")
    else:
      return other


6

Hoşuma gitti Munch'u nokta erişiminin üstünde birçok kullanışlı seçenek sunuyor.

ithal munch

temp_1 = {'person': {'fname': 'senthil', 'lname': 'ramalingam'}}

dict_munch = munch.munchify (temp_1)

dict_munch.person.fname


6

Geçenlerde aynı şeyi yapan ' Box ' kütüphanesine rastladım .

Kurulum komutu: pip install python-box

Misal:

from box import Box

mydict = {"key1":{"v1":0.375,
                    "v2":0.625},
          "key2":0.125,
          }
mydict = Box(mydict)

print(mydict.key1.v1)

Ben büyük iç içe dicts olduğunda python özyineleme hatası üreten dotmap gibi diğer mevcut kütüphanelerden daha etkili bulundu.

kitaplık ve ayrıntılara bağlantı: https://pypi.org/project/python-box/


5

Kullanımı __getattr__, çok basit, Python 3.4.3'te çalışıyor

class myDict(dict):
    def __getattr__(self,val):
        return self[val]


blockBody=myDict()
blockBody['item1']=10000
blockBody['item2']="StackOverflow"
print(blockBody.item1)
print(blockBody.item2)

Çıktı:

10000
StackOverflow

4

Dilin kendisi bunu desteklemez, ancak bazen bu hala yararlı bir gereksinimdir. Demet tarifinin yanı sıra, noktalı bir dize kullanarak bir sözlüğe erişebilen küçük bir yöntem de yazabilirsiniz:

def get_var(input_dict, accessor_string):
    """Gets data from a dictionary using a dotted accessor-string"""
    current_data = input_dict
    for chunk in accessor_string.split('.'):
        current_data = current_data.get(chunk, {})
    return current_data

ki böyle bir şeyi destekleyecekti:

>> test_dict = {'thing': {'spam': 12, 'foo': {'cheeze': 'bar'}}}
>> output = get_var(test_dict, 'thing.spam.foo.cheeze')
>> print output
'bar'
>>

4

Epool'un cevabı üzerine inşa etmek için, bu sürüm nokta operatörü aracılığıyla içerideki herhangi bir diksiyona erişmenizi sağlar:

foo = {
    "bar" : {
        "baz" : [ {"boo" : "hoo"} , {"baba" : "loo"} ]
    }
}

Örneğin, foo.bar.baz[1].babageri döner "loo".

class Map(dict):
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    if isinstance(v, dict):
                        v = Map(v)
                    if isinstance(v, list):
                        self.__convert(v)
                    self[k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                if isinstance(v, dict):
                    v = Map(v)
                elif isinstance(v, list):
                    self.__convert(v)
                self[k] = v

    def __convert(self, v):
        for elem in xrange(0, len(v)):
            if isinstance(v[elem], dict):
                v[elem] = Map(v[elem])
            elif isinstance(v[elem], list):
                self.__convert(v[elem])

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

1
Python 3: yerine iteritems()ile items()ve xrange()ilerange()
sasawatc

3
def dict_to_object(dick):
    # http://stackoverflow.com/a/1305663/968442

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

    return Struct(**dick)

Eğer kişi bunu kalıcı dictolarak nesneye dönüştürmeye karar verirse bunu yapmalıdır. Erişimden hemen önce bir bırakma nesnesi oluşturabilirsiniz.

d = dict_to_object(d)

def attr (** kwargs): o = lambda: Yok o .__ dict __. güncelleme (** kwargs) dönüş o
throws_exceptions_at_you

2

Ben İKİ çalışırken sona erdi AttrDict ve Bunchve bunları kullanımlarım için yavaşlatmanın yolunu 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 istek süremin sırasıyla 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, ancak bu işlevselliği kodunuzda biraz kullanıyorsanız,

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.


0

Kendi çözümümü ringe atmak istiyorum:

https://github.com/skorokithakis/jsane

JSON'a erişebileceğiniz bir şeyle ayrıştırmanıza izin verir with.attribute.lookups.like.this.r(), çünkü çoğunlukla bu cevabı üzerinde çalışmaya başlamadan önce görmemiştim.


Python birkaç sinir bozucu basit tasarım hatalarından suçlu, yetiştirme KeyErrorbunlardan biri, Biri olmayan bir anahtara eriştiğinde tek yapması Nonegereken JS davranışına benzer. Hem okuma hem de yazma için büyük bir otovivasyon hayranıyım. Kütüphaneniz ideale en yakın.
nehem

0

OP sorusuna doğrudan bir cevap değil, ama bazıları için ilham ve belki de yararlı .. dahili kullanarak nesne tabanlı bir çözüm oluşturdum __dict__(Hiçbir şekilde optimize edilmiş kod)

payload = {
    "name": "John",
    "location": {
        "lat": 53.12312312,
        "long": 43.21345112
    },
    "numbers": [
        {
            "role": "home",
            "number": "070-12345678"
        },
        {
            "role": "office",
            "number": "070-12345679"
        }
    ]
}


class Map(object):
    """
    Dot style access to object members, access raw values
    with an underscore e.g.

    class Foo(Map):
        def foo(self):
            return self.get('foo') + 'bar'

    obj = Foo(**{'foo': 'foo'})

    obj.foo => 'foobar'
    obj._foo => 'foo'

    """

    def __init__(self, *args, **kwargs):
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self.__dict__[k] = v
                    self.__dict__['_' + k] = v

        if kwargs:
            for k, v in kwargs.iteritems():
                self.__dict__[k] = v
                self.__dict__['_' + k] = v

    def __getattribute__(self, attr):
        if hasattr(self, 'get_' + attr):
            return object.__getattribute__(self, 'get_' + attr)()
        else:
            return object.__getattribute__(self, attr)

    def get(self, key):
        try:
            return self.__dict__.get('get_' + key)()
        except (AttributeError, TypeError):
            return self.__dict__.get(key)

    def __repr__(self):
        return u"<{name} object>".format(
            name=self.__class__.__name__
        )


class Number(Map):
    def get_role(self):
        return self.get('role')

    def get_number(self):
        return self.get('number')


class Location(Map):
    def get_latitude(self):
        return self.get('lat') + 1

    def get_longitude(self):
        return self.get('long') + 1


class Item(Map):
    def get_name(self):
        return self.get('name') + " Doe"

    def get_location(self):
        return Location(**self.get('location'))

    def get_numbers(self):
        return [Number(**n) for n in self.get('numbers')]


# Tests

obj = Item({'foo': 'bar'}, **payload)

assert type(obj) == Item
assert obj._name == "John"
assert obj.name == "John Doe"
assert type(obj.location) == Location
assert obj.location._lat == 53.12312312
assert obj.location._long == 43.21345112
assert obj.location.latitude == 54.12312312
assert obj.location.longitude == 44.21345112

for n in obj.numbers:
    assert type(n) == Number
    if n.role == 'home':
        assert n.number == "070-12345678"
    if n.role == 'office':
        assert n.number == "070-12345679"

0

Nokta erişimi almanın (ancak dizi erişimi değil) basit bir yolu, Python'da düz bir nesne kullanmaktır. Bunun gibi:

class YourObject:
    def __init__(self, *args, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

... ve şu şekilde kullanın:

>>> obj = YourObject(key="value")
>>> print(obj.key)
"value"

... bunu bir dikteye dönüştürmek için:

>>> print(obj.__dict__)
{"key": "value"}

0

Bu çözüm, OP'nin iç içe diktelere tutarlı bir şekilde erişme gereksinimini karşılamak için epool tarafından sunulan çözüm üzerinde bir ayrıntılandırmadır . Epool tarafından çözüm, iç içe dikte erişim için izin vermedi.

class YAMLobj(dict):
    def __init__(self, args):
        super(YAMLobj, self).__init__(args)
        if isinstance(args, dict):
            for k, v in args.iteritems():
                if not isinstance(v, dict):
                    self[k] = v
                else:
                    self.__setattr__(k, YAMLobj(v))


    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(YAMLobj, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(YAMLobj, self).__delitem__(key)
        del self.__dict__[key]

Bu sınıfa ile, bir anda böyle bir şey yapabilirsiniz: A.B.C.D.


0

Bu aynı zamanda iç içe diklerle de çalışır ve daha sonra eklenen dikmelerin aynı şekilde davranmasını sağlar:

class DotDict(dict):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Recursively turn nested dicts into DotDicts
        for key, value in self.items():
            if type(value) is dict:
                self[key] = DotDict(value)

    def __setitem__(self, key, item):
        if type(item) is dict:
            item = DotDict(item)
        super().__setitem__(key, item)

    __setattr__ = __setitem__
    __getattr__ = dict.__getitem__

0

@ Derek73'ün cevabı çok temizdir , ancak turşu veya (derin) kopyalanamaz ve Noneeksik anahtarlar için geri döner . Aşağıdaki kod bunu düzeltir.

Düzenleme: Ben yukarıdaki aynı noktayı (yukarı oy) adres cevabı görmedim. Cevabı referans için burada bırakıyorum.

class dotdict(dict):
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

-1

Bir çözüm türü hassas

class DotDict(dict):

    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

    def __getattr__(self, key):

        def typer(candidate):
            if isinstance(candidate, dict):
                return DotDict(candidate)

            if isinstance(candidate, str):  # iterable but no need to iter
                return candidate

            try:  # other iterable are processed as list
                return [typer(item) for item in candidate]
            except TypeError:
                return candidate

            return candidate

        return typer(dict.get(self, key))
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.