Convertir un multiplet nommé en dictionnaire

148

J'ai une classe de tuple nommée en python

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

J'aimerais convertir les instances de Town en dictionnaires. Je ne veux pas qu'il soit strictement lié aux noms ou au nombre de champs dans une ville.

Existe-t-il un moyen de l'écrire de telle sorte que je puisse ajouter plus de champs, ou passer un tuple nommé entièrement différent et obtenir un dictionnaire.

Je ne peux pas modifier la définition de classe d'origine car elle est dans le code de quelqu'un d'autre. Je dois donc prendre une instance d'une ville et la convertir en dictionnaire.

Sans moi, c'est juste Aweso
la source
2
btw ... regardez la complétion de l'onglet ou la dircommande, qui vous montrera les champs pour n'importe quel objet ... qui aurait montré la _asdictfonction directement.
Corley Brigman
il semble que ce que vous voulez vraiment faire est une sous-classe de dictau lieu de 'namedtuple', et passez le namedtuple dans l'initialiseur. N'oubliez pas que si vous êtes habitué à Cxx, ce class Town(x)n'est pas le constructeur, à l' def __init__(self, *args, **kwargs)intérieur.
Corley Brigman
Je ne peux pas modifier la classe d'origine car elle est dans le code de quelqu'un d'autre. donc je dois sous-classer de namedtouble
Without Me It Just Aweso
@CorleyBrigman pouvez-vous expliquer cela plus? J'ai essayé de trouver de la documentation sur le touple nommé, ou de trouver ce que je pouvais appeler dessus et je ne pouvais pas comprendre comment. (Encore une fois, le python n'est pas mon langage le plus fort)
Without Me It Just Aweso
2
quelle partie? direst juste un python intégré ... vous pouvez l'exécuter sur n'importe quel objet python, dans une console ou dans un script (où il renvoie une liste que vous pouvez imprimer ou faire quoi que ce soit avec), et il renverra une liste de (presque ) tous les attributs de l'objet. utile si vous essayez de comprendre comment fonctionne un objet inconnu.
Corley Brigman

Réponses:

268

TL; DR: une méthode est _asdictfournie pour cela.

Voici une démonstration de l'utilisation:

>>> 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')])

C'est une méthode documentée de namedtuples, c'est-à-dire contrairement à la convention habituelle en python, le trait de soulignement principal sur le nom de la méthode n'est pas là pour décourager l'utilisation . Avec les autres méthodes ajoutées à namedtuples, _make, _replace, _source, _fields, il a souligné que pour essayer de prévenir les conflits avec les noms de champs possibles.


Remarque: pour certains codes 2.7.5 <python version <3.5.0 à l'état sauvage, vous pouvez voir cette version:

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

Pendant un certain temps, la documentation avait mentionné que _asdictc'était obsolète (voir ici ), et suggéré d'utiliser la méthode intégrée vars . Cet avis est maintenant dépassé; afin de corriger un bug lié au sous- __dict__classement , la propriété qui était présente sur les namedtuples a de nouveau été supprimée par ce commit .

wim
la source
1
Est-ce que quelqu'un sait s'il existe un précédent établi qui suggère de _asdictne pas être aliasé dans la bibliothèque standard asdict?
KobeJohn
1
@KobeJohn alors vous ne pouviez pas "asdict"être l'un des noms de tuple.
shadowtalker
28

Il existe une méthode intégrée sur les namedtupleinstances pour cela _asdict,.

Comme discuté dans les commentaires, sur certaines versions le vars()fera également, mais cela dépend apparemment fortement des détails de construction, alors qu'il _asdictdevrait être fiable. Dans certaines versions a _asdictété marqué comme obsolète, mais les commentaires indiquent que ce n'est plus le cas à partir de la 3.4.

Peter DeGlopper
la source
1
Je n'étais pas le downvoter, mais cela pourrait être parce que la _asdictméthode a été obsolète dans python3 (en faveur de vars)
wim
Inversement, il semble que varscela ne fonctionne pas sur certaines versions plus anciennes - sur 2.7, cela déclenche un TypeError, car la namedtupleclasse de cette version n'a pas d' __dict__attribut.
Peter DeGlopper
oui, Martijn et moi en avons discuté ici . Cela fonctionnera sur les nouvelles versions de 2.7 btw (je suis sur 2.7.6 et cela fonctionne)
wim
Passé la fenêtre d'édition sur mon commentaire ci-dessus - il échoue sur 2.7.5 donc il doit être nouveau à partir de 2.7.6. À moins que ma version 2.7.5 ne soit désactivée, comme Martijn était à la réponse liée? Quoi qu'il en soit, il semble que cela fonctionne ou non sur 2.7.5 dépend des spécificités de la construction.
Peter DeGlopper
8
Juste un avertissement: _asdict n'est plus obsolète (et retourne un OrderedDict maintenant), et vars produit une erreur avec Python 3.4 (à partir de la suppression de l' attribut dict de namedtuples).
Alexander Huszagh
2

Sur les versions Ubuntu 14.04 LTS de python2.7 et python3.4, la __dict__propriété fonctionnait comme prévu. La _asdict méthode a également fonctionné, mais je suis enclin à utiliser l'API de propriété uniforme définie par les normes au lieu de l'API non uniforme localisée.

$ 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

Voir comme dict est la manière sémantique d'obtenir un dictionnaire représentant quelque chose, (du moins à ma connaissance).


Ce serait bien d'accumuler un tableau des principales versions et plates-formes de python et de leur support pour __dict__, actuellement je n'ai qu'une version de plate-forme et deux versions de python comme indiqué ci-dessus.

| 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
la source
1
Linux-3.10.0-693.el7.x86_64-x86_64-with-centos-7.4.1708-Core, Python 2.7 - __dict__ne fonctionne pas.
gbtimmon
-1

Cas n ° 1: tuple à une dimension

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" 

Cas n ° 2: tuple à deux dimensions
Exemple: DICT_ROLES [961] # affichera '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()
yongtaek jun
la source
-1

si aucun _asdict (), vous pouvez utiliser cette méthode:

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
la source
-5

Python 3. Allouez n'importe quel champ au dictionnaire comme index requis pour le dictionnaire, j'ai utilisé «nom».

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}
André Odendaal
la source
Pas utile car vous savez que le nom est là. ça devrait être une méthode aveugle
Mitchell Currie