Перетворіть nametuple в словник


148

У мене названий клас кортежів у python

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

Я хотів би перетворити екземпляри Town у словники. Я не хочу, щоб він жорстко прив’язувався до імен чи кількості полів у місті.

Чи є спосіб написати це так, щоб я міг додати більше полів або передати зовсім інший названий кортеж і отримати словник.

Я не можу змінити початкове визначення класу як його в чужому коді. Тому мені потрібно взяти екземпляр міста та перетворити його у словник.


2
btw ... подивіться на завершення вкладки або dirкоманду, яка покаже вам поля для будь-якого об'єкта ..., який би показав _asdictфункцію безпосередньо.
Корлі Бригман

схоже, те, що ви насправді хочете зробити, це підклас із dictзамість 'nametuple' та передайте найменування nametuple в ініціалізатор. Пам'ятайте, що якщо ви звикли до Cxx, class Town(x)це не конструктор, def __init__(self, *args, **kwargs)всередині він є.
Корлі Бригман

Я не можу змінити оригінальний клас як його в коді elses. тому я маю підклас від namedtouble
Без мене це просто Aweso

@CorleyBrigman Ви можете пояснити це більше? Я спробував знайти документацію на названий тупл або знайти те, що я міг би викликати, і не міг зрозуміти, як це зробити. (Знову python - це не моя найсильніша мова)
Без мене це просто Aweso

2
яка частина? dirце просто вбудований пітон ... ви можете запустити його на будь-якому об’єкті python, в консолі чи сценарії (де він повертає список, який ви можете надрукувати або зробити все, що завгодно), і він поверне список (майже ) всі атрибути об’єкта. корисно, якщо ви намагаєтеся з’ясувати, як працює невідомий об’єкт.
Корлі Бригман

Відповіді:


268

TL; DR: _asdictдля цього передбачений метод .

Ось демонстрація використання:

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

Це задокументований метод namedtuples, тобто, на відміну від звичайної конвенції в python, провідна підкреслення назви методу не існує, щоб відмовитись від використання . Поряд з іншими методами доданих до namedtuples, _make, _replace, _source, _fields, тобто підкреслення тільки , щоб спробувати запобігти конфліктам з можливими іменами полів.


Примітка. Для деяких 2.7.5 <python версії <3.5.0 код у дикій природі, ви можете бачити цю версію:

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

Деякий час у документації згадувалося про _asdictзастаріле (див. Тут ), і пропонували використовувати вбудований метод vars . Ця порада застаріла; для того , щоб виправити помилку , пов'язану з підкласами, то __dict__майно , яке було присутнє на namedtuples знову було видалено цієї фіксації .


1
Хтось знає, чи є _asdictв стандартній бібліотеці встановлений прецедент, який говорить про те, що не слід залишати його asdict?
KobeJohn

1
@KobeJohn, тоді ви не могли "asdict"бути одним із прізвищ кортежу.
shadowtalker

28

Там є вбудований метод на namedtupleвипадках для цього _asdict.

Як було обговорено в коментарях, у деяких версіях vars()це також вдасться зробити, але це, мабуть, сильно залежить від деталей складання, тоді як _asdictповинно бути надійним. У деяких версіях _asdictбуло позначено як застаріле, але коментарі вказують, що це так вже не стосується 3.4.


1
Я не був прихильником, але це могло бути тому, що _asdictметод був застарілий у python3 (на користь vars)
wim

І навпаки, схоже, що це не varsпрацює на деяких старих версіях - у 2.7 він піднімає a TypeError, оскільки namedtupleклас цієї версії не має __dict__атрибута.
Пітер ДеГлоппер

так, ми з Мартіїном тут обговорювали це . Він працюватиме на новіших версіях 2,7 btw (я на 2,7,6 і це працює)
wim

Минуле вікно редагування на моєму вище коментарі - воно не працює на 2.7.5, тому воно повинно бути новим з 2.7.6. Якщо моя збірка 2.7.5 не вимкнена, як Мартійн був на відповідь? У будь-якому випадку, схоже, працює він на 2.7.5, залежить від специфіки побудови.
Пітер ДеГлоппер

8
Лише вгору: _присуд більше не нав'язується (і тепер повертає OrdersDict), і vars створює помилку з Python 3.4 (від видалення атрибута dict з namedtuples).
Олександр Хузаг

2

У версіях Ubuntu 14.04 LTS python2.7 та python3.4 __dict__властивість працювала як очікувалося. _asdict Метод працював, але я схильний використовувати стандартизовану певні, обмундирування, властивість апі замість локалізованої нерівномірною апі.

$ 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

Бачачи , як Dict це семантичний спосіб отримати словник , який представляє soemthing, (принаймні , наскільки мені відомо).


Було б непогано зібрати таблицю основних версій і платформ python та їх підтримку __dict__, на даний момент у мене є лише одна версія платформи та дві версії python, як розміщено вище.

| 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__не працює.
gbtimmon

-1

Справа №1: один розмірний кортеж

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" 

Випадок №2
: Двомірний кортеж Приклад: DICT_ROLES [961] # відобразиться "Задній програміст"

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

якщо немає _asdict (), ви можете використовувати такий спосіб:

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. Виділіть будь-яке поле до словника як необхідний індекс для словника, я використав '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}

Не корисно, як відомо, ім'я там є. це повинен бути сліпий метод
Мітчелл Керрі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.