Converti una coppia con nome in un dizionario


148

Ho una classe tupla nominata in Python

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

Vorrei convertire le istanze di Town in dizionari. Non voglio che sia rigidamente legato ai nomi o al numero dei campi in una città.

C'è un modo per scriverlo in modo che io possa aggiungere più campi o passare una tupla di nome completamente diversa e ottenere un dizionario.

Non posso modificare la definizione della classe originale come nel codice di qualcun altro. Quindi ho bisogno di prendere un'istanza di una città e convertirla in un dizionario.


2
btw ... guarda il completamento della scheda o il dircomando, che ti mostrerà i campi per qualsiasi oggetto ... che avrebbe mostrato _asdictdirettamente la funzione.
Corley Brigman,

sembra che quello che vuoi veramente fare sia una sottoclasse dictinvece di 'namedtuple', e passare la namedtuple nell'inizializzatore. Ricorda che se sei abituato a Cxx, class Town(x)non è il costruttore, def __init__(self, *args, **kwargs)al suo interno lo è.
Corley Brigman,

Non posso modificare la classe originale come è nel codice di qualcun altro. quindi devo sottoclassare da nametouble
Without Me It Just Aweso,

@CorleyBrigman puoi spiegarlo di più? Ho cercato di trovare la documentazione sul touple con nome, o trovare quello che potevo chiamare e non sono riuscito a capire come. (Ancora una volta Python non è il mio linguaggio più forte)
Without Me It Just Aweso,

2
che parte? dirè solo un python integrato ... puoi eseguirlo su qualsiasi oggetto python, in una console o in uno script (dove restituisce un elenco che puoi stampare o fare qualunque cosa), e restituirà un elenco di (quasi ) tutti gli attributi dell'oggetto. utile se stai cercando di capire come funziona un oggetto sconosciuto.
Corley Brigman,

Risposte:


268

TL; DR: esiste un metodo _asdictper questo.

Ecco una dimostrazione dell'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')])

Questo è un metodo documentato di nametuples, cioè a differenza della solita convenzione in Python il carattere di sottolineatura principale sul nome del metodo non è lì per scoraggiare l'uso . Insieme con gli altri metodi aggiunti namedtuples, _make, _replace, _source, _fields, ha la sottolineatura solo per cercare di prevenire i conflitti con i possibili nomi di campo.


Nota: per alcuni 2.7.5 <versione di Python <3.5.0 in circolazione in natura, potresti vedere questa versione:

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

Per un po 'la documentazione aveva affermato che _asdictera obsoleta (vedi qui ) e suggeriva di usare il metodo integrato var . Tale consiglio è ora obsoleto; per correggere un bug relativo alla sottoclasse, la __dict__proprietà che era presente su namedtuples è stata nuovamente rimossa da questo commit .


1
Qualcuno sa se esiste un precedente stabilito che suggerisce che _asdictnon dovrebbe essere modificato nella libreria standard asdict?
KobeJohn,

1
@KobeJohn allora non avresti potuto "asdict"essere uno dei nomi delle tuple.
Shadowtalker,

28

C'è un metodo integrato nelle namedtupleistanze per questo _asdict,.

Come discusso nei commenti, su alcune versioni lo vars()farà anche, ma apparentemente dipende fortemente dai dettagli di costruzione, mentre _asdictdovrebbe essere affidabile. In alcune versioni è _asdictstato contrassegnato come obsoleto, ma i commenti indicano che non è più il caso a partire dalla 3.4.


1
Non ero il downvoter, ma potrebbe essere perché il _asdictmetodo è stato obsoleto nella python3 (a favore di Vars)
Wim

Al contrario, sembra che non varsfunzioni su alcune versioni precedenti - su 2.7 genera a TypeError, poiché la namedtupleclasse di quella versione non ha un __dict__attributo.
Peter DeGlopper,

sì, Martijn e io ne abbiamo discusso qui . Funzionerà con le versioni più recenti di 2.7 btw (sono la 2.7.6 e funziona)
wim

Passato la finestra di modifica sul mio commento sopra - fallisce su 2.7.5 quindi deve essere nuovo a partire da 2.7.6. A meno che la mia build 2.7.5 non sia disattivata, come quella di Martijn era alla risposta collegata? Ad ogni modo, sembra che funzioni o meno sulla 2.7.5 dipende dalle specifiche della build.
Peter DeGlopper,

8
Solo un avvertimento: _asdict non è più ostruito (e restituisce un OrderedDict ora), e vars produce un errore con Python 3.4 (dalla rimozione dell'attributo dict di namedtuples).
Alexander Huszagh,

2

Su Ubuntu 14.04 versioni LTS di python2.7 e python3.4 la __dict__proprietà ha funzionato come previsto. Anche il _asdict metodo ha funzionato, ma sono propenso a usare l'API di proprietà standardizzata, uniforme, anziché l'API non uniforme localizzata.

$ 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

Vedere come dict è il modo semantico per ottenere un dizionario che rappresenti tutto (almeno per quanto ne so).


Sarebbe bello accumulare una tabella delle principali versioni e piattaforme di Python e il loro supporto __dict__, al momento ho solo una versione di piattaforma e due versioni di Python come pubblicato sopra.

| 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     |

1
Linux-3.10.0-693.el7.x86_64-x86_64-with-centos-7.4.1708-Core, Python 2.7 - __dict__non funziona.
gbtimmon,

-1

Caso n. 1: tupla a una dimensione

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 n. 2: tupla a due dimensioni
Esempio: DICT_ROLES [961] # mostrerà 'Back-End Programmer'

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()

-1

se no _asdict (), puoi usare in questo modo:

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

-5

Python 3. Allocare qualsiasi campo al dizionario come indice richiesto per il dizionario, ho usato 'nome'.

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}

Non utile come sai il nome è lì. dovrebbe essere un metodo cieco
Mitchell Currie
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.