Przekonwertuj namedtuple na słownik

148

Mam nazwaną klasę krotki w Pythonie

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

Chciałbym zamienić instancje Town na słowniki. Nie chcę, aby było to sztywno związane z nazwami lub liczbą pól w mieście.

Czy istnieje sposób na zapisanie go w taki sposób, że mógłbym dodać więcej pól lub przekazać zupełnie inną nazwaną krotkę i uzyskać słownik.

Nie mogę zmienić oryginalnej definicji klasy, ponieważ znajduje się w czyimś kodzie. Muszę więc pobrać wystąpienie Town i przekonwertować je na słownik.

Beze mnie to tylko aweso
źródło
2
btw ... spójrz na uzupełnianie tabulatorów lub dirpolecenie, które pokaże pola dla dowolnego obiektu ... który _asdictbezpośrednio pokazałby funkcję.
Corley Brigman
wygląda na to, że to, co naprawdę chcesz zrobić, to podklasa z dictzamiast „namedtuple” i przekazanie namedtuple do inicjatora. Pamiętaj, że jeśli jesteś przyzwyczajony do Cxx, class Town(x)to nie konstruktor, ale w def __init__(self, *args, **kwargs)środku jest.
Corley Brigman
Nie mogę zmienić oryginalnej klasy, ponieważ jest w czyimś kodzie. więc muszę podklasę z namedtouble
Without Me It Just Aweso
@CorleyBrigman Czy możesz to wyjaśnić bardziej? Próbowałem znaleźć dokumentację dotyczącą nazwanej pary lub znaleźć to, do czego mógłbym się odwołać, ale nie mogłem dowiedzieć się, jak to zrobić. (Ponownie python nie jest moim najsilniejszym językiem)
Without Me It Just Aweso
2
Która część? dirjest po prostu wbudowanym pythonem ... możesz go uruchomić na dowolnym obiekcie Pythona, w konsoli lub w skrypcie (gdzie zwraca listę, którą możesz wydrukować lub zrobić cokolwiek), a zwróci listę (prawie ) wszystkie atrybuty obiektu. przydatne, jeśli próbujesz dowiedzieć się, jak działa nieznany obiekt.
Corley Brigman,

Odpowiedzi:

268

TL; DR: istnieje na to metoda _asdict.

Oto demonstracja użycia:

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

Jest to udokumentowana metoda namedtuples, tj. W przeciwieństwie do zwykłej konwencji w Pythonie, wiodący znak podkreślenia w nazwie metody nie ma zniechęcać do używania . Wraz z innymi metodami dodawanych do namedtuples, _make, _replace, _source, _fields, ma podkreślenia tylko spróbować i uniknąć ewentualnych konfliktów z nazwami pól.


Uwaga: w przypadku kodu 2.7.5 <python w wersji <3.5.0 na wolności możesz zobaczyć tę wersję:

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

Przez chwilę dokumentacja wspominała, że _asdictjest przestarzała (patrz tutaj ) i sugerowała użycie wbudowanej metody vars . Ta rada jest teraz nieaktualna; aby naprawić błąd związany z podklasami, __dict__właściwość, która była obecna w namedtuples, została ponownie usunięta przez to zatwierdzenie .

wim
źródło
1
Czy ktoś wie, czy istnieje ustalony precedens, który sugeruje, że _asdictnie powinien być aliasowany w bibliotece standardowej asdict?
KobeJohn
1
@KobeJohn to nie mógłbyś "asdict"być jednym z nazwisk krotki.
shadowtalker
28

Istnieje wbudowana metoda w namedtupleinstancjach do tego _asdict,.

Jak omówiono w komentarzach, w niektórych wersjach vars()również to zrobi, ale najwyraźniej jest to wysoce zależne od szczegółów kompilacji, podczas gdy _asdictpowinno być niezawodne. W niektórych wersjach _asdictzostał oznaczony jako przestarzałe, ale komentarze wskazują, że nie ma to już miejsca od 3.4.

Peter DeGlopper
źródło
1
Nie byłem przeciwnikiem, ale mogło to być spowodowane tym, że _asdictmetoda została przestarzała w pythonie3 (na korzyść vars)
wim
I odwrotnie, wygląda na to, że varsnie działa na niektórych starszych wersjach - w wersji 2.7 podnosi a TypeError, ponieważ namedtupleklasa tej wersji nie ma __dict__atrybutu.
Peter DeGlopper
tak, Martijn i ja omówiliśmy to tutaj . Będzie działać na nowszych wersjach 2.7 btw (jestem na 2.7.6 i działa)
wim
Poza oknem edycji w moim powyższym komentarzu - nie działa w wersji 2.7.5, więc musi być nowy od 2.7.6. Chyba że moja kompilacja 2.7.5 jest wyłączona, tak jak Martijn w połączonej odpowiedzi? W każdym razie wydaje się, że to, czy działa w wersji 2.7.5, zależy od specyfiki kompilacji.
Peter DeGlopper
8
Uwaga: _asdict nie jest już przestarzały (i zwraca teraz OrderedDict), a vars generuje błąd w Pythonie 3.4 (z powodu usunięcia atrybutu dict z namedtuples).
Alexander Huszagh
2

W wersjach python2.7 i python3.4 Ubuntu 14.04 LTS __dict__właściwość działała zgodnie z oczekiwaniami. _asdict Metoda również działa, ale jestem skłonny do korzystania z określonych standardach, jednolity, nieruchomości API zamiast zlokalizowanej niejednorodnego API.

$ 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

Postrzeganie jako dykt jest semantycznym sposobem na uzyskanie słownika reprezentującego wszystko (przynajmniej według mojej najlepszej wiedzy).


Byłoby miło zgromadzić tabelę głównych wersji Pythona i platform oraz ich wsparcia __dict__, obecnie mam tylko jedną wersję platformy i dwie wersje Pythona, jak napisano powyżej.

| 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
źródło
1
Linux-3.10.0-693.el7.x86_64-x86_64-with-centos-7.4.1708-Core, Python 2.7 - __dict__nie działa.
gbtimmon
-1

Przypadek 1: krotka jednowymiarowa

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" 

Przypadek 2:
Krotka dwuwymiarowa Przykład: DICT_ROLES [961] # pokaże „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
źródło
-1

jeśli nie ma _asdict (), możesz użyć tego sposobu:

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
źródło
-5

Python 3. Przydziel dowolne pole do słownika jako wymagany indeks słownika, użyłem '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
źródło
Nie jest pomocne, ponieważ wiesz, że jest tam imię. powinna to być metoda ślepa
Mitchell Currie