2010-06-13 15 views
23

Bunun gibi bir şey yapmak isterim:Dict erişiminin yanı sıra öznitelikler aracılığıyla özyinelemeye erişir?

from dotDict import dotdictify 

life = {'bigBang': 
      {'stars': 
       {'planets': []} 
      } 
     } 

dotdictify(life) 

# This would be the regular way: 
life['bigBang']['stars']['planets'] = {'earth': {'singleCellLife': {}}} 
# But how can we make this work? 
life.bigBang.stars.planets.earth = {'singleCellLife': {}} 

#Also creating new child objects if none exist, using the following syntax: 
life.bigBang.stars.planets.earth.multiCellLife = {'reptiles':{},'mammals':{}} 

Benim motivasyonları kodun özünü arttırmaktır ve eğer mümkünse verimli çapraz platform geliştirme için JSON nesnelerine erişmek için Javascript'e benzer sözdizimi kullanın. (Py2JS ve benzerlerini de kullanıyorum.)

+0

'life.bigBang.stars.planets' bir' listesi'ni tanımlanır, bu nedenle atama onun '.earth' özniteliği bir' AttributeError: 'listesiyle sonuçlanır' listenin 'nesnesi' earth 'özelliğine sahip değildir. Tahmin ediyorum ki, muhtemelen 'yaşam' sözlüğünün tanımında (kabul edilen cevapta gösterildiği gibi) '{' gezegenler ': {}}' demek istiyorsunuz. – martineau

cevap

41

İşte tecrübe bu tür oluşturmak için bir yolu şudur: soyunmuş Curt Hagenlocher ait cevap esinlenerek iç içe geçmiş bir nitelik sözlük (başka bir uygulanmasına Aşağıda

class DotDictify(dict): 
    MARKER = object() 

    def __init__(self, value=None): 
     if value is None: 
      pass 
     elif isinstance(value, dict): 
      for key in value: 
       self.__setitem__(key, value[key]) 
     else: 
      raise TypeError('expected dict') 

    def __setitem__(self, key, value): 
     if isinstance(value, dict) and not isinstance(value, DotDictify): 
      value = DotDictify(value) 
     super(DotDictify, self).__setitem__(key, value) 

    def __getitem__(self, key): 
     found = self.get(key, DotDictify.MARKER) 
     if found is DotDictify.MARKER: 
      found = DotDictify() 
      super(DotDictify, self).__setitem__(key, found) 
     return found 

    __setattr__, __getattr__ = __setitem__, __getitem__ 


if __name__ == '__main__': 

    life = {'bigBang': 
       {'stars': 
        {'planets': {} # Value changed from [] 
        } 
       } 
      } 

    life = DotDictify(life) 
    print(life.bigBang.stars.planets) # -> [] 
    life.bigBang.stars.planets.earth = {'singleCellLife' : {}} 
    print(life.bigBang.stars.planets) # -> {'earth': {'singleCellLife': {}}} 
+5

Arama dict .__ setitem __ (öz, anahtar, değer) eksik olduğum yinelemenin hilesidir! Oldukça zarif kodlar var efendim :) –

+1

Siz (ve @Luke) 'dict .__ setitem __ (self, key, value) 'yerine' super (dotdictify, self) .__ setitem __ (anahtar, değer)' kullanmalısınız (aksi takdirde sizinkilerin alt sınıflarıdır) birden fazla ata sahip olanların başı belaya girer). Ve (builtins hariç) sınıflar, –

+0

@TobiasKienzler ile başlamalıdır –

0

) esansiyel:

Bu Python 2 hem çalışır
class AttrDict(dict): 
    """ Nested Attribute Dictionary 

    A class to convert a nested Dictionary into an object with key-values 
    accessibly using attribute notation (AttrDict.attribute) in addition to 
    key notation (Dict["key"]). This class recursively sets Dicts to objects, 
    allowing you to recurse down nested dicts (like: AttrDict.attr.attr) 
    """ 

    def __init__(self, mapping): 
     super(AttrDict, self).__init__() 
     for key, value in mapping.items(): 
      self.__setitem__(key, value) 

    def __setitem__(self, key, value): 
     if isinstance(value, dict): 
      value = AttrDict(value) 
     super(AttrDict, self).__setitem__(key, value) 

    def __getattr__(self, item): 
     try: 
      return self.__getitem__(item) 
     except KeyError: 
      raise AttributeError(item) 

    __setattr__ = __setitem__ 

ve 3:

life = AttrDict({'bigBang': {'stars': {'planets': {}}}}) 
life['bigBang']['stars']['planets'] = {'earth': {'singleCellLife': {}}} 
life.bigBang.stars.planets.earth.multiCellLife = {'reptiles': {}, 'mammals': {}} 
print(life.bigBang.stars.planets.earth) 
# -> {'singleCellLife': {}, 'multiCellLife': {'mammals': {}, 'reptiles': {}}} 

__getattr__ yılında AttributeError içine KeyError dönüştürme hasattr eserler de durumda öznitelik bulunamazsa şekilde Python3 gereklidir:

hasattr(life, 'parallelUniverse') 
# --> False 
İlgili konular