Estou procurando uma maneira elegante de obter dados usando o acesso a atributos em um dict com alguns dict e listas aninhados (ou seja, sintaxe de objeto no estilo javascript).
Por exemplo:
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
Deve ser acessível desta maneira:
>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar
Eu acho que isso não é possível sem recursão, mas qual seria uma boa maneira de obter um estilo de objeto para ditados?
python
object
dictionary
Marc
fonte
fonte
from_
e não de_from
acordo com o PEP 8 .getattr(x, 'from')
vez de renomear o atributo.d1.b.c
), acho claro que você deve usar algo de uma biblioteca, por exemplo, nomeado o dobro de coleções , como sugere esta resposta . .Respostas:
Atualização: No Python 2.6 em diante, considere se a
namedtuple
estrutura de dados atende às suas necessidades:A alternativa (conteúdo original da resposta) é:
Então, você pode usar:
fonte
Struct
s aninhados a partir de dicionários aninhados, mas em geral o tipo do valor pode ser qualquer coisa. Chave está restrita a ser adequado para uma ranhura objetoargparse.Namespace
(que também tem definidos__eq__
,__ne__
,__contains__
).fonte
if isinstance(b, (list, tuple)):
obj
classe deargparse.Namespace
para recursos adicionais, como representação de seqüência de caracteres legível.Surpreendentemente, ninguém mencionou Bunch . Essa biblioteca destina-se exclusivamente a fornecer acesso no estilo de atributo a objetos dict e faz exatamente o que o OP deseja. Uma demonstração:
Uma biblioteca Python 3 está disponível em https://github.com/Infinidat/munch - O crédito vai para codyzu
fonte
adicione recursão a isso e pronto.
editar é assim que eu o implementaria:
fonte
top_instance = top()
e retornar para onde você voltatop
?x
e osx.b
que retornam feios #<class '__main__.new'>
Existe um auxiliar de coleta chamado
namedtuple
, que pode fazer isso por você:fonte
Pode ser usado com qualquer estrutura de sequência / ditado / valor de qualquer profundidade.
fonte
def __repr__(self): return '{%s}' % str(', '.join("'%s': %s" % (k, repr(v)) for (k, v) in self.__dict__.iteritems()))
.items()
em vez de.iteritems()
na linha 4. (A função foi renomeado, mas faz essencialmente a mesma )Tomando o que considero os melhores aspectos dos exemplos anteriores, eis o que eu criei:
fonte
def __init__(self, dct): for k, v in dct.iteritems(): setattr(self, k, isinstance(v, dict) and self.__class__(v) or v)
que também remove a chamada explícita paraStruct
isinstance(v, dict)
cheque seria melhor comoisinstance(v, collections.Mapping)
para que ele possa lidar com futuro dict-like coisasSe seu ditado é proveniente
json.loads()
, você pode transformá-lo em um objeto (em vez de um ditado) em uma linha:Consulte também Como converter dados JSON em um objeto Python .
fonte
.loads
se você tem um enorme objeto JSONSe você deseja acessar chaves dict como um objeto (ou dict para chaves difíceis), faça-o recursivamente e também possa atualizar o dict original, você pode:
Exemplo de uso:
fonte
fonte
Eu acabei tentando AMBOS o AttrDict e o Bunchbibliotecas e as achei muito lentas para meus usos. Depois que um amigo e eu examinamos, descobrimos que o método principal para escrever essas bibliotecas resulta na recorrência agressiva da biblioteca através de um objeto aninhado e na criação de cópias do objeto de dicionário. Com isso em mente, fizemos duas mudanças importantes. 1) Criamos atributos com carregamento lento 2) em vez de criar cópias de um objeto de dicionário, criamos cópias de um objeto proxy leve. Esta é a implementação final. O aumento de desempenho do uso desse código é incrível. Ao usar o AttrDict ou o Bunch, essas duas bibliotecas por si só consumiram 1/2 e 1/3, respectivamente, do meu tempo de solicitação (o que !?). Esse código reduziu esse tempo para quase nada (em algum lugar na faixa de 0,5ms). Isso, é claro, depende das suas necessidades,
Veja a implementação original aqui em https://stackoverflow.com/users/704327/michael-merickel .
A outra coisa a observar é que essa implementação é bastante simples e não implementa todos os métodos que você pode precisar. Você precisará gravá-las conforme necessário nos objetos DictProxy ou ListProxy.
fonte
x.__dict__.update(d)
deve fazer bem.fonte
__dict__
: tentativaobject().__dict__
e você vai terAttributeError: 'object' object has no attribute '__dict__'
Você pode aproveitar o
json
módulo da biblioteca padrão com um gancho de objeto personalizado :Exemplo de uso:
E não é estritamente somente leitura como é
namedtuple
, ou seja, você pode alterar valores - não estrutura:fonte
json.JSONEncoder
eobject_hook
.Isso deve começar:
Ainda não funciona para listas. Você precisará agrupar as listas em uma UserList e sobrecarregar
__getitem__
para agrupar os dict.fonte
if isinstance(d, list)
cláusula daAnon
resposta.Eu sei que já existem muitas respostas aqui e estou atrasado para a festa, mas esse método recursivamente e 'no lugar' converterá um dicionário em uma estrutura semelhante a objeto ... Funciona no 3.xx
fonte
fonte
Deixe-me explicar uma solução que quase usei há algum tempo. Mas primeiro, a razão pela qual não o fiz é ilustrada pelo fato de o seguinte código:
dá este erro:
Como "from" é uma palavra-chave Python, existem certas chaves de dicionário que você não pode permitir.
Agora, minha solução permite o acesso aos itens do dicionário usando seus nomes diretamente. Mas também permite que você use "semântica de dicionário". Aqui está o código com o exemplo de uso:
fonte
Perguntas e respostas antigas, mas tenho mais alguma coisa para conversar. Parece que ninguém fala sobre ditado recursivo. Este é o meu código:
fonte
Queria fazer upload da minha versão deste pequeno paradigma.
Ele preserva os atributos para o tipo que é importado para a classe. Minha única preocupação seria substituir métodos de dentro do dicionário que você analisou. Mas por outro lado parece sólido!
fonte
df.a
nem funciona.Isso também funciona bem também
fonte
Aqui está outra maneira de implementar a sugestão original do SilentGhost:
fonte
Eu me deparei com o caso de que precisava converter recursivamente uma lista de dictos em lista de objetos; portanto, com base no snippet de Roberto aqui, o que funcionou para mim:
Observe que qualquer tupla será convertida em sua lista equivalente, por razões óbvias.
Espero que isso ajude alguém tanto quanto todas as suas respostas fizeram por mim, pessoal.
fonte
Que tal apenas atribuir o seu
dict
ao__dict__
objeto vazio?Obviamente, isso falhará no exemplo de dict aninhado, a menos que você siga o dict recursivamente:
E seu elemento de lista de exemplo provavelmente deveria ser um
Mapping
, uma lista de pares (chave, valor) como este:fonte
Aqui está outra implementação:
[Editar] Falta pouco sobre também lidar com dict dentro de listas, não apenas em outros dict. Correção adicionada.
fonte
Uso:
fonte
Que tal agora:
Isso pode ser usado assim:
fonte
Eu acho que um ditado consiste em número, string e ditado é suficiente na maioria das vezes. Portanto, ignoro a situação em que tuplas, listas e outros tipos não aparecem na dimensão final de um ditado.
Considerando a herança, combinada com a recursão, resolve o problema de impressão de maneira conveniente e também fornece duas maneiras de consultar dados, uma maneira de editar os dados.
Veja o exemplo abaixo, um ditado que descreve algumas informações sobre os alunos:
Resultados:
fonte
Normalmente, você deseja espelhar a hierarquia de ditados no seu objeto, mas não a lista ou as tuplas que estão normalmente no nível mais baixo. Então é assim que eu fiz isso:
Então fazemos:
e pegue:
x.b.b1.x
1x.c
['oi', 'bar']fonte
Meu dicionário é deste formato:
Como pode ser visto, aninhei dicionários e lista de ditados . Isso ocorre porque o addr_bk foi decodificado a partir dos dados do buffer do protocolo que foram convertidos em um dict python usando lwpb.codec. Existem campos opcionais (por exemplo, email => onde a chave pode estar indisponível) e campos repetidos (por exemplo, telefone => convertidos em lista de ditados).
Eu tentei todas as soluções propostas acima. Alguns não lidam bem com os dicionários aninhados. Outros não podem imprimir os detalhes do objeto facilmente.
Somente a solução, dict2obj (dict) de Dawie Strauss, funciona melhor.
Eu o aprimorei um pouco para lidar quando a chave não pode ser encontrada:
Então, eu testei com:
fonte
Criando minha resposta para " python: como adicionar propriedade a uma classe dinamicamente? ":
Você chama
makedata
o dicionário que deseja converter, ou talveztrydata
dependendo do que espera como entrada, e ele cospe um objeto de dados.Notas:
trydata
se precisar de mais funcionalidade.x.a = {}
ou algo semelhante.fonte