Converter um nomeado duplo em um dicionário

148

Eu tenho uma classe de tupla nomeada em python

class Town(collections.namedtuple('Town', [
    'name', 
    'population',
    'coordinates',
    'population', 
    'capital', 
    'state_bird'])):
    # ...

Gostaria de converter instâncias do Town em dicionários. Não quero que ele esteja rigidamente vinculado aos nomes ou ao número dos campos de uma cidade.

Existe uma maneira de escrevê-lo de forma que eu possa adicionar mais campos ou passar uma tupla nomeada totalmente diferente e obter um dicionário.

Não posso alterar a definição de classe original como está no código de outra pessoa. Então, preciso pegar uma instância de uma cidade e convertê-la em um dicionário.

Sem mim, apenas Aweso
fonte
2
btw ... veja a conclusão da guia ou o dircomando, que mostrará os campos para qualquer objeto ... que mostraria a _asdictfunção diretamente.
Corley Brigman
parece que o que você realmente deseja fazer é subclasse de em dictvez de 'namedtuple' e passar o nomeduplo para o inicializador. Lembre-se de que, se você está acostumado ao Cxx, class Town(x)não é o construtor, está def __init__(self, *args, **kwargs)dentro dele.
Corley Brigman
Não posso alterar a classe original, pois está no código de alguém. então eu tenho que subclasse de namedtouble
Without Me It Just Aweso
@CorleyBrigman, você pode explicar isso mais? Tentei encontrar documentação sobre o toque nomeado, ou encontrar o que eu poderia chamar e não consegui descobrir como. (Novamente python não é a minha linguagem mais forte)
Without Me It Just Aweso
2
qual parte? diré apenas um python embutido ... você pode executá-lo em qualquer objeto python, em um console ou em um script (onde retorna uma lista com a qual você pode imprimir ou fazer o que quer que seja) e retornará uma lista de (quase ) todos os atributos do objeto. útil se você estiver tentando descobrir como um objeto desconhecido funciona.
Corley Brigman

Respostas:

268

TL; DR: existe um método _asdictfornecido para isso.

Aqui está uma demonstração do uso:

>>> fields = ['name', 'population', 'coordinates', 'capital', 'state_bird']
>>> Town = collections.namedtuple('Town', fields)
>>> funkytown = Town('funky', 300, 'somewhere', 'lipps', 'chicken')
>>> funkytown._asdict()
OrderedDict([('name', 'funky'),
             ('population', 300),
             ('coordinates', 'somewhere'),
             ('capital', 'lipps'),
             ('state_bird', 'chicken')])

Este é um método documentado de nomeados simples, ou seja, diferente da convenção usual em python, o sublinhado principal no nome do método não existe para desencorajar o uso . Junto com os outros métodos adicionados ao namedtuples, _make, _replace, _source, _fields, tem o sublinhado só para tentar evitar conflitos com possíveis nomes de campo.


Nota: Para algum código 2.7.5 <python versão <3.5.0 disponível, você pode ver esta versão:

>>> vars(funkytown)
OrderedDict([('name', 'funky'),
             ('population', 300),
             ('coordinates', 'somewhere'),
             ('capital', 'lipps'),
             ('state_bird', 'chicken')])

Por um tempo, a documentação mencionou que _asdictestava obsoleta (veja aqui ) e sugeriu o uso dos vars do método interno . Esse conselho agora está desatualizado; para corrigir um erro relacionado à subclasse, a __dict__propriedade presente nos nomeados foi removida novamente por esse commit .

wim
fonte
1
Alguém sabe se existe um precedente estabelecido que sugere _asdictque não deva ser aliasado na biblioteca padrão asdict?
KobeJohn
1
@KobeJohn, então você não poderia "asdict"ser um dos nomes das tuplas.
shadowtalker
28

Existe um método embutido nas namedtupleinstâncias para isso _asdict,.

Conforme discutido nos comentários, em algumas versões vars()também o fará, mas aparentemente é altamente dependente dos detalhes da compilação, embora _asdictdeva ser confiável. Em algumas versões, _asdictfoi marcado como obsoleto, mas os comentários indicam que esse não é mais o caso a partir do 3.4.

Peter DeGlopper
fonte
1
Eu não era o downvoter, mas poderia ser porque o _asdictmétodo foi tornado obsoleto em python3 (em favor de vars)
Wim
Por outro lado, parece que varsnão funciona em algumas versões mais antigas - no 2.7, gera a TypeError, já que a namedtupleclasse dessa versão não possui um __dict__atributo.
Peter DeGlopper
Sim, Martijn e eu discutimos isso aqui . Ele vai trabalhar em versões mais recentes de 2,7 btw (eu estou em 2.7.6 e funciona)
Wim
Após a janela de edição no meu comentário acima - ele falha no 2.7.5, portanto deve ser novo a partir do 2.7.6. A menos que minha compilação 2.7.5 esteja desativada, como a de Martijn estava na resposta vinculada? De qualquer forma, parece que funciona ou não no 2.7.5 depende de detalhes da compilação.
Peter DeGlopper
8
Apenas um aviso: _asdict não está mais obsoleto (e retorna um OrderedDict agora) e o vars produz um erro no Python 3.4 (a partir da remoção do atributo dict dos nomeados).
Alexander Huszagh
2

No Ubuntu 14.04, versões LTS do python2.7 e python3.4, a __dict__propriedade funcionava conforme o esperado. O _asdict método também funcionou, mas estou inclinado a usar a API de propriedade uniforme, definida por padrões, em vez da API não uniforme localizada.

$ python2.7

# Works on:
# Python 2.7.6 (default, Jun 22 2015, 17:58:13)  [GCC 4.8.2] on linux2
# Python 3.4.3 (default, Oct 14 2015, 20:28:29)  [GCC 4.8.4] on linux

import collections

Color = collections.namedtuple('Color', ['r', 'g', 'b'])
red = Color(r=256, g=0, b=0)

# Access the namedtuple as a dict
print(red.__dict__['r'])  # 256

# Drop the namedtuple only keeping the dict
red = red.__dict__
print(red['r'])  #256

Ver como ditado é a maneira semântica de obter um dicionário representando algo, (pelo menos até onde sei).


Seria bom acumular uma tabela das principais versões e plataformas de python e seu suporte __dict__, atualmente só tenho uma versão de plataforma e duas versões de python, conforme publicado acima.

| Platform                      | PyVer     | __dict__ | _asdict |
| --------------------------    | --------- | -------- | ------- |
| Ubuntu 14.04 LTS              | Python2.7 | yes      | yes     |
| Ubuntu 14.04 LTS              | Python3.4 | yes      | yes     |
| CentOS Linux release 7.4.1708 | Python2.7 | no       | yes     |
| CentOS Linux release 7.4.1708 | Python3.4 | no       | yes     |
| CentOS Linux release 7.4.1708 | Python3.6 | no       | yes     |
ThorSummoner
fonte
1
Linux-3.10.0-693.el7.x86_64-x86_64-with-centos-7.4.1708-Core, Python 2.7 - __dict__não funciona.
Gbtimmon
-1

Caso # 1: tupla de uma dimensão

TUPLE_ROLES = (
    (912,"Role 21"),
    (913,"Role 22"),
    (925,"Role 23"),
    (918,"Role 24"),
)


TUPLE_ROLES[912]  #==> Error because it is out of bounce. 
TUPLE_ROLES[  2]  #==> will show Role 23.
DICT1_ROLE = {k:v for k, v in TUPLE_ROLES }
DICT1_ROLE[925] # will display "Role 23" 

Caso 2: tupla de duas dimensões
Exemplo: DICT_ROLES [961] # mostrará 'Programador de Back-End'

NAMEDTUPLE_ROLES = (
    ('Company', ( 
            ( 111, 'Owner/CEO/President'), 
            ( 113, 'Manager'),
            ( 115, 'Receptionist'),
            ( 117, 'Marketer'),
            ( 119, 'Sales Person'),
            ( 121, 'Accountant'),
            ( 123, 'Director'),
            ( 125, 'Vice President'),
            ( 127, 'HR Specialist'),
            ( 141, 'System Operator'),
    )),
    ('Restaurant', ( 
            ( 211, 'Chef'), 
            ( 212, 'Waiter/Waitress'), 
    )),
    ('Oil Collector', ( 
            ( 211, 'Truck Driver'), 
            ( 213, 'Tank Installer'), 
            ( 217, 'Welder'),
            ( 218, 'In-house Handler'),
            ( 219, 'Dispatcher'),
    )),
    ('Information Technology', ( 
            ( 912, 'Server Administrator'),
            ( 914, 'Graphic Designer'),
            ( 916, 'Project Manager'),
            ( 918, 'Consultant'),
            ( 921, 'Business Logic Analyzer'),
            ( 923, 'Data Model Designer'),
            ( 951, 'Programmer'),
            ( 953, 'WEB Front-End Programmer'),
            ( 955, 'Android Programmer'),
            ( 957, 'iOS Programmer'),
            ( 961, 'Back-End Programmer'),
            ( 962, 'Fullstack Programmer'),
            ( 971, 'System Architect'),
    )),
)

#Thus, we need dictionary/set

T4 = {}
def main():
    for k, v in NAMEDTUPLE_ROLES:
        for k1, v1 in v:
            T4.update ( {k1:v1}  )
    print (T4[961]) # will display 'Back-End Programmer'
    # print (T4) # will display all list of dictionary

main()
yongtaek jun
fonte
-1

se não _asdict (), você pode usar desta maneira:

def to_dict(model):
    new_dict = {}
    keys = model._fields
    index = 0
    for key in keys:
        new_dict[key] = model[index]
        index += 1

    return new_dict
Ebubekir Tabak
fonte
-5

Python 3. Aloque qualquer campo para o dicionário como o índice necessário para o dicionário, usei 'name'.

import collections

Town = collections.namedtuple("Town", "name population coordinates capital state_bird")

town_list = []

town_list.append(Town('Town 1', '10', '10.10', 'Capital 1', 'Turkey'))
town_list.append(Town('Town 2', '11', '11.11', 'Capital 2', 'Duck'))

town_dictionary = {t.name: t for t in town_list}
Andre Odendaal
fonte
Não é útil como você sabe o nome está lá. ele deve ser um método cego
Mitchell Currie