Convert nested Python dict to object?

后端 未结 30 2455
时光取名叫无心
时光取名叫无心 2020-11-22 09:28

I\'m searching for an elegant way to get data using attribute access on a dict with some nested dicts and lists (i.e. javascript-style object syntax).

For example:

30条回答
  •  独厮守ぢ
    2020-11-22 10:11

    My dictionary is of this format:

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

    As can be seen, I have nested dictionaries and list of dicts. This is because the addr_bk was decoded from protocol buffer data that converted to a python dict using lwpb.codec. There are optional field (e.g. email => where key may be unavailable) and repeated field (e.g. phone => converted to list of dict).

    I tried all the above proposed solutions. Some doesn't handle the nested dictionaries well. Others cannot print the object details easily.

    Only the solution, dict2obj(dict) by Dawie Strauss, works best.

    I have enhanced it a little to handle when the key cannot be found:

    # 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
    

    Then, I tested it with:

    # 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
    

提交回复
热议问题