Como faço para tornar os membros do dicionário Python acessíveis através de um ponto "."?
Por exemplo, em vez de escrever mydict['val']
, eu gostaria de escrever mydict.val
.
Também gostaria de acessar dict aninhados dessa maneira. Por exemplo
mydict.mydict2.val
se referiria a
mydict = { 'mydict2': { 'val': ... } }
python
dictionary
syntax
nested
bodacydo
fonte
fonte
d[a][b][c]
é substituído pord[a, b, c]
.{"my.key":"value"}
? Ou quando a chave é uma palavra-chave, como "de"? Já o considerei algumas vezes, e são mais problemas e solução de problemas do que benefícios percebidos.Respostas:
Você pode fazer isso usando essa classe que acabei de criar. Com essa classe, você pode usar o
Map
objeto como outro dicionário (incluindo serialização json) ou com a notação de ponto. Espero ajudá-lo:Exemplos de uso:
fonte
.iteritems()
para.items()
AttributeError
se o atributo não existir. Em vez disso, ele retornaráNone
.self.update(*args,**kwargs)
. Além disso, você pode adicionar__missing__(self,key): value=self[key]= type(self)(); return value
. Em seguida, você pode adicionar entradas ausentes usando a notação de ponto. Se você quiser que ele seja selecionável, você pode adicionar__getstate__
e__setstate__
hasattr(Map, 'anystring') is true. which means the hasattr would always return True due to overriding
__getattr__`Eu sempre mantive isso em um arquivo util. Você pode usá-lo como um mixin em suas próprias classes também.
fonte
d = {'foo': {'bar': 'baz'}}; d = dotdict(d); d.foo.bar
lança um erro de atributo, masd.foo
funciona bem.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__
get
é realmente uma má ideia, uma vez que vai voltarNone
em vez de elevar um erro para itens em falta ...Instalar
dotmap
viapip
Ele faz tudo o que você quer que faça e subclasses
dict
, para que funcione como um dicionário normal:Além disso, você pode convertê-lo para e de
dict
objetos:Isso significa que, se algo que você deseja acessar já está em
dict
forma, você pode transformá-lo em umDotMap
para facilitar o acesso:Por fim, ele cria automaticamente novas
DotMap
instâncias filho para que você possa fazer coisas assim:Comparação com Bunch
Divulgação completa: Sou o criador do DotMap . Eu o criei porque
Bunch
estavam faltando esses recursosDotMap
criação automática de filhos , que economiza tempo e cria um código mais limpo quando você tem muita hierarquiadict
conversão recursiva de todas asdict
instâncias filhas paraDotMap
fonte
{"test.foo": "bar"}
pode ser acessado viamymap.test.foo
Isso seria fantástico. Levará alguma regressão para converter um mapa plano em um mapa profundo e aplicar o DotMap a ele, mas vale a pena!DotMap
com preenchimento automático funciona melhor. Uso Sublime Text, que preenche automaticamente as palavras-chave digitadas anteriormente.**kwargs
ouc = {**a, **b}
. De fato, falha silenciosamente, se comporta como um dicionário vazio ao extrair.m = DotMap(); m.a = 2; m.b = 3; print('{a} {b}'.format(**m));
e obtive o esperado2 3
. Se você tem um caso quebrado comprovado que funciona paradict()
mas nãoDotMap()
, envie seu código para a guia Problemas no GitHub.Derivar do ditado ee implementar
__getattr__
e__setattr__
.Ou você pode usar o Bunch, que é muito semelhante.
Eu não acho que é possível monkeypatch classe dict interno.
fonte
O Fabric possui uma implementação realmente agradável e mínima . Estendendo isso para permitir acesso aninhado, podemos usar
defaultdict
ae o resultado é algo como isto:Faça uso da seguinte maneira:
Isso explica um pouco a resposta de Kugel de "Derivar do ditado ee implementar
__getattr__
e__setattr__
". Agora você sabe como!fonte
dotdict
que permite converterdict
objetos existentes recursivamente: gist.github.com/miku/…Eu tentei isso:
você pode tentar
__getattribute__
também.faça de cada dict um tipo de dotdict seria bom o suficiente; se você deseja iniciar isso a partir de um dict de várias camadas, tente implementar
__init__
também.fonte
def docdict(name):
antes e depois `se isinstance (nome, dict): retorno DotDict (nome) Nome do retorno`class 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]
Não. O acesso a atributos e a indexação são coisas separadas no Python, e você não deve querer que elas executem o mesmo. Faça uma classe (possivelmente uma feita por
namedtuple
) se você tiver algo que deva ter atributos acessíveis e use[]
notação para obter um item de um ditado.fonte
.
vez de[]
acessar estruturas de dados complicadas nos modelos Mako.Se você deseja selecionar seu dicionário modificado, precisará adicionar alguns métodos de estado às respostas acima:
fonte
__getattr__ = dict.get
Com base na resposta de Kugel e levando em consideração as palavras de cautela de Mike Graham, e se fizermos um invólucro?
fonte
Use
SimpleNamespace
:fonte
Gosto do Munch e oferece muitas opções úteis sobre o acesso a pontos.
fonte
Recentemente, me deparei com a biblioteca ' Box ', que faz a mesma coisa.
Comando de instalação:
pip install python-box
Exemplo:
Eu achei que era mais eficaz do que outras bibliotecas existentes, como o dotmap, que geram erro de recursão em python quando você tem dict aninhados grandes.
link para a biblioteca e detalhes: https://pypi.org/project/python-box/
fonte
Use
__getattr__
, muito simples, funciona em Python 3.4.3Resultado:
fonte
O idioma em si não suporta isso, mas às vezes isso ainda é um requisito útil. Além da receita do Bunch, você também pode escrever um pequeno método que pode acessar um dicionário usando uma string pontilhada:
que suportaria algo como isto:
fonte
Para basear-se na resposta do epool, esta versão permite acessar qualquer dict interno através do operador dot:
Por exemplo,
foo.bar.baz[1].baba
retorna"loo"
.fonte
iteritems()
poritems()
exrange()
comrange()
Se alguém decidir convertê-lo permanentemente
dict
em objeto, isso deve fazer. Você pode criar um objeto descartável antes de acessar.fonte
Eu acabei tentando AMBOS o AttrDict e o Bunchbibliotecas e achei que elas eram uma maneira lenta de usar meus usos. Depois que um amigo e eu analisamos, 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 carregados preguiçosamente 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 consumiram apenas 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). Obviamente, isso depende das suas necessidades, mas se você estiver usando essa funcionalidade bastante no seu código,
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
Eu gostaria de jogar minha própria solução no ringue:
https://github.com/skorokithakis/jsane
Ele permite analisar o JSON em algo que você pode acessar
with.attribute.lookups.like.this.r()
, principalmente porque eu não tinha visto essa resposta antes de começar a trabalhar nela.fonte
KeyError
é um deles. Quando alguém acessa a chave que não existe, tudo o que precisa fazer é retornarNone
semelhante ao comportamento do JS. Sou um grande fã de autovivificação tanto para leitura quanto para escrita. Sua biblioteca está mais próxima do ideal.Não é uma resposta direta à pergunta do OP, mas inspirada e talvez útil para alguns. Criei uma solução baseada em objeto usando o interno
__dict__
(código de maneira alguma otimizado)fonte
Uma maneira simples de obter acesso a pontos (mas não a matriz) é usar um objeto simples no Python. Como isso:
... e use-o assim:
... para convertê-lo em um ditado:
fonte
Essa solução é um refinamento da proposta pelo epool para atender ao requisito do OP de acessar dicts aninhados de maneira consistente. A solução por epool não permitiu acessar dicts aninhados.
Com esta classe, pode-se agora fazer algo como:
A.B.C.D
.fonte
Isso também funciona com dicts aninhados e garante que os dices anexados posteriormente se comportem da mesma maneira:
fonte
A resposta de @ derek73 é muito elegante, mas não pode ser decapada nem copiada (em profundidade) e retorna
None
para as chaves ausentes. O código abaixo corrige isso.Editar: eu não vi a resposta acima que aborda exatamente o mesmo ponto (votado). Estou deixando a resposta aqui para referência.
fonte
Uma solução meio delicada
fonte