template dict create python oop dictionary getattr

python - create - Acceso recursivo dict a través de los atributos, así como el acceso al índice?



dict django (2)

Me gustaría poder hacer algo como esto:

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

Mis motivaciones son mejorar la brevedad del código y, si es posible, usar una sintaxis similar a Javascript para acceder a los objetos JSON para un desarrollo cruzado eficiente. (También uso Py2JS y similares).


Debajo de otra implementación de un diccionario de atributos anidados (inspirado en la respuesta de Curt Hagenlocher, desglosado en lo esencial):

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__

Esto funciona tanto en Python 2 como en 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'': {}}}

La conversión de KeyError en AttributeError en __getattr__ es necesaria en Python3 de modo que hasattr funcione también en caso de que no se encuentre el atributo:

hasattr(life, ''parallelUniverse'') # --> False


Esta es una forma de crear ese tipo de experiencia:

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