Convierte una tupla nombrada en un diccionario

148

Tengo una clase de tupla con nombre en Python

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

Me gustaría convertir las instancias de Town en diccionarios. No quiero que esté rígidamente vinculado a los nombres o al número de campos en una ciudad.

¿Hay alguna manera de escribirlo para poder agregar más campos o pasar una tupla con un nombre completamente diferente y obtener un diccionario?

No puedo alterar la definición de clase original como está en el código de otra persona. Entonces necesito tomar una instancia de una ciudad y convertirla en un diccionario.

Sin mí, simplemente Aweso
fuente
2
por cierto ... mire la finalización de la pestaña o el dircomando, que le mostrará los campos para cualquier objeto ... que hubiera mostrado la _asdictfunción directamente.
Corley Brigman
parece que lo que realmente quieres hacer es una subclase en dictlugar de 'namedtuple' y pasar la namedtuple al inicializador. Recuerda que si estás acostumbrado a Cxx, class Town(x)no es el constructor, def __init__(self, *args, **kwargs)dentro está.
Corley Brigman
No puedo alterar la clase original ya que está en el código de otra persona. así que tengo que subclase de namedtouble
Sin mí, es simplemente impresionante
@CorleyBrigman, ¿puedes explicar esto más? Traté de encontrar documentación en el touple nombrado, o encontrar lo que podía llamar y no pude averiguar cómo. (Nuevamente, Python no es mi lenguaje más fuerte)
Sin mí, es simplemente impresionante
2
¿qué parte? dires solo un python incorporado ... puede ejecutarlo en cualquier objeto de python, en una consola o en un script (donde devuelve una lista que puede imprimir o hacer lo que sea), y devolverá una lista de (casi ) todos los atributos del objeto. útil si está tratando de descubrir cómo funciona un objeto desconocido.
Corley Brigman

Respuestas:

268

TL; DR: hay un método _asdictprovisto para esto.

Aquí hay una demostración del 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 es un método documentado de nombre de tuplas, es decir, a diferencia de la convención habitual en Python, el guión bajo del nombre del método no está ahí para desalentar su uso . Junto con los otros métodos añadidos a namedtuples, _make, _replace, _source, _fields, tiene el carácter de subrayado sólo para tratar de evitar conflictos con los nombres de los campos posibles.


Nota: Para algunos códigos 2.7.5 <versión de python <3.5.0 en estado salvaje, es posible que vea esta versión:

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

Durante un tiempo la documentación había mencionado que _asdictera obsoleto (ver aquí ), y sugirió utilizar la incorporada en el método de vars . Ese consejo ahora está desactualizado; Para corregir un error relacionado con la subclasificación, esta confirmación__dict__ ha eliminado nuevamente la propiedad que estaba presente en namedtuples .

wim
fuente
1
¿Alguien sabe si hay un precedente establecido que sugiera _asdictque no debería tener un alias en la biblioteca estándar asdict?
KobeJohn
1
@ KobeJohn, entonces no podrías haber "asdict"sido uno de los nombres de las tuplas.
shadowtalker
28

Hay un método incorporado en namedtupleinstancias para esto _asdict,.

Como se discutió en los comentarios, en algunas versiones vars()también lo hará, pero aparentemente depende en gran medida de los detalles de construcción, aunque _asdictdebería ser confiable. En algunas versiones _asdictse marcó como obsoleto, pero los comentarios indican que este ya no es el caso a partir de 3.4.

Peter DeGlopper
fuente
1
No era el votante negativo, pero podría deberse a que el _asdictmétodo ha quedado obsoleto en python3 (a favor de vars)
wim
Por el contrario, parece que no varsfunciona en algunas versiones anteriores: en 2.7 genera una TypeError, ya que la namedtupleclase de esa versión no tiene un __dict__atributo.
Peter DeGlopper el
Sí, Martijn y yo hemos discutido eso aquí . Funcionará en versiones más nuevas de 2.7 por cierto (estoy en 2.7.6 y funciona)
wim
Más allá de la ventana de edición en mi comentario anterior, falla en 2.7.5, por lo que debe ser nuevo a partir de 2.7.6. A menos que mi versión 2.7.5 esté desactivada, ya que Martijn estaba en la respuesta vinculada. De todos modos, parece que si funciona o no en 2.7.5 depende de los detalles de la construcción.
Peter DeGlopper
8
Solo un aviso: _asdict ya no se obselecta (y ahora devuelve un OrderedDict), y vars produce un error con Python 3.4 (al eliminar el dict atributo de namedtuples).
Alexander Huszagh el
2

En las versiones Ubuntu 14.04 LTS de python2.7 y python3.4, la __dict__propiedad funcionó como se esperaba. El _asdict método también funcionó, pero me inclino a usar la API de propiedad uniforme y definida por estándares en lugar de la API no 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 dict es la forma semántica de obtener un diccionario que represente algo, (al menos a mi leal saber y entender).


Sería bueno acumular una tabla de las principales versiones y plataformas de Python y su soporte para __dict__, actualmente solo tengo una versión de plataforma y dos versiones de Python como se publicó anteriormente.

| 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
fuente
1
Linux-3.10.0-693.el7.x86_64-x86_64-with-centos-7.4.1708-Core, Python 2.7 - __dict__no funciona.
gbtimmon
-1

Caso # 1: tupla de una dimensión

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 dos dimensiones
Ejemplo: DICT_ROLES [961] # mostrará 'Programador de fondo'

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

si no _asdict (), puede usarlo de esta manera:

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

Python 3. Asignar cualquier campo al diccionario como el índice requerido para el diccionario, utilicé 'nombre'.

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
fuente
No es útil ya que sabes que el nombre está ahí. debería ser un método ciego
Mitchell Currie