Konvertieren Sie ein benanntes Tupel in ein Wörterbuch

147

Ich habe eine benannte Tupelklasse in Python

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

Ich möchte Town-Instanzen in Wörterbücher konvertieren. Ich möchte nicht, dass es fest mit den Namen oder der Nummer der Felder in einer Stadt verbunden ist.

Gibt es eine Möglichkeit, es so zu schreiben, dass ich weitere Felder hinzufügen oder ein ganz anderes benanntes Tupel übergeben und ein Wörterbuch erhalten kann?

Ich kann die ursprüngliche Klassendefinition nicht wie im Code eines anderen ändern. Also muss ich eine Instanz einer Stadt nehmen und sie in ein Wörterbuch konvertieren.

Ohne mich ist es einfach Aweso
quelle
2
Übrigens ... sehen Sie sich die Tab-Vervollständigung oder den dirBefehl an, der Ihnen die Felder für jedes Objekt anzeigt ... das die _asdictFunktion direkt angezeigt hätte .
Corley Brigman
Es sieht so aus, als ob Sie wirklich eine Unterklasse von dictanstelle von 'namedtuple' verwenden und das namedtuple an den Initialisierer übergeben möchten. Denken Sie daran, dass, wenn Sie an Cxx gewöhnt sind, class Town(x)nicht der Konstruktor def __init__(self, *args, **kwargs)darin ist.
Corley Brigman
Ich kann die ursprüngliche Klasse nicht ändern, da sie in einem anderen Code enthalten ist. Also muss ich eine Unterklasse von namedtouble
Ohne mich ist es nur Aweso
@ CorleyBrigman kannst du das mehr erklären? Ich habe versucht, Dokumentation zu dem genannten Touple zu finden oder herauszufinden, wie ich es aufrufen kann, und ich konnte nicht herausfinden, wie. (Wieder Python ist nicht meine stärkste Sprache)
Ohne mich ist es einfach Aweso
2
welcher Teil? dirist nur ein integrierter Python ... Sie können es auf jedem Python-Objekt, in einer Konsole oder in einem Skript ausführen (wo es eine Liste zurückgibt, die Sie drucken oder mit was auch immer tun können), und es wird eine Liste von (fast) zurückgeben ) alle Attribute des Objekts. hilfreich, wenn Sie herausfinden möchten, wie ein unbekanntes Objekt funktioniert.
Corley Brigman

Antworten:

267

TL; DR: Hierfür wird eine Methode _asdictbereitgestellt.

Hier ist eine Demonstration der Verwendung:

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

Dies ist eine dokumentierte Methode für benannte Tupel, dh im Gegensatz zu der in Python üblichen Konvention ist der führende Unterstrich des Methodennamens nicht dazu da, die Verwendung zu verhindern . Zusammen mit den anderen Methoden zu namedtuples hinzugefügt _make, _replace, _source, _fields, hat es den Unterstrich nur zu versuchen und zu verhindern , dass Konflikte mit möglichen Feldnamen.


Hinweis: Für einige 2.7.5 <Python-Version <3.5.0-Code in freier Wildbahn wird möglicherweise folgende Version angezeigt:

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

Für eine Weile hatte die Dokumentation erwähnt, dass dies _asdictveraltet war (siehe hier ), und vorgeschlagen, die eingebaute Methode vars zu verwenden . Dieser Rat ist jetzt veraltet; Um einen Fehler im Zusammenhang mit Unterklassen zu beheben , wurde die __dict__Eigenschaft, die in namedtuples vorhanden war, durch dieses Commit erneut entfernt .

wim
quelle
1
Weiß jemand, ob es einen etablierten Präzedenzfall gibt, der vorschlägt, _asdictnicht in der Standardbibliothek zu aliasen asdict?
KobeJohn
1
@KobeJohn dann könntest du nicht "asdict"einer der Tupelnamen sein .
Shadowtalker
28

Es gibt eine eingebaute Methode für namedtupleInstanzen dafür _asdict.

Wie in den Kommentaren besprochen, wird dies bei einigen Versionen vars()ebenfalls der _asdictFall sein , aber es hängt anscheinend stark von den Build-Details ab, sollte jedoch zuverlässig sein. In einigen Versionen _asdictwurde dies als veraltet markiert, aber Kommentare weisen darauf hin, dass dies ab 3.4 nicht mehr der Fall ist.

Peter DeGlopper
quelle
1
Ich war nicht der Downvoter, aber es könnte sein, dass die _asdictMethode in Python3 (zugunsten von Vars) veraltet ist
wim
Umgekehrt sieht es so aus, als varswürde es bei einigen älteren Versionen nicht funktionieren - bei 2.7 wird ein a ausgelöst TypeError, da die namedtupleKlasse dieser Version kein __dict__Attribut hat.
Peter DeGlopper
Ja, Martijn und ich haben das hier besprochen . Es wird auf neueren Versionen von 2.7 btw funktionieren (ich bin auf 2.7.6 und es funktioniert)
wim
Nach dem Bearbeitungsfenster in meinem obigen Kommentar schlägt es in 2.7.5 fehl, daher muss es ab 2.7.6 neu sein. Es sei denn, mein 2.7.5 Build ist ausgeschaltet, da Martijn bei der verknüpften Antwort war? Wie auch immer, es scheint so, als ob es unter 2.7.5 funktioniert oder nicht, hängt von den Build-Besonderheiten ab.
Peter DeGlopper
8
Nur ein Hinweis: _asdict wird nicht mehr blockiert (und gibt jetzt ein OrderedDict zurück), und vars erzeugt einen Fehler mit Python 3.4 (durch Entfernen des dict- Attributs von namedtuples).
Alexander Huszagh
2

Unter Ubuntu 14.04 LTS-Versionen von python2.7 und python3.4 funktionierte die __dict__Eigenschaft wie erwartet. Die _asdict Methode hat auch funktioniert, aber ich bin geneigt, die durch Standards definierte, einheitliche Eigenschafts-API anstelle der lokalisierten, nicht einheitlichen API zu verwenden.

$ 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

Sehen als dict ist die semantische Art und Weise ein Wörterbuch darstellt soemthing zu bekommen, (zumindest auf meinem besten Wissen).


Es wäre schön, eine Tabelle der wichtigsten Python-Versionen und -Plattformen und deren Unterstützung für zu sammeln. __dict__Derzeit habe ich nur eine Plattformversion und zwei Python-Versionen, wie oben angegeben.

| 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
quelle
1
Linux-3.10.0-693.el7.x86_64-x86_64-with-centos-7.4.1708-Core, Python 2.7 - __dict__funktioniert nicht.
Gbtimmon
-1

Fall 1: eindimensionales Tupel

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" 

Fall 2: Zweidimensionales Tupel
Beispiel: DICT_ROLES [961] # zeigt 'Back-End-Programmierer' an.

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

Wenn kein _asdict () vorhanden ist, können Sie Folgendes verwenden:

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

Python 3. Ordnen Sie dem Wörterbuch ein beliebiges Feld als erforderlichen Index für das Wörterbuch zu. Ich habe 'name' verwendet.

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
quelle
Nicht hilfreich, da Sie wissen, dass der Name vorhanden ist. Es sollte eine blinde Methode sein
Mitchell Currie