Преобразовать именованный кортеж в словарь


148

У меня есть названный класс кортежа в Python

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

Я хотел бы преобразовать экземпляры Town в словари. Я не хочу, чтобы он был жестко привязан к именам или количеству полей в городе.

Есть ли способ написать это так, чтобы я мог добавить больше полей или передать совершенно другой именованный кортеж и получить словарь.

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


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

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

Я не могу изменить исходный класс, как его в чей-то другой код. так что я должен подкласс от namedtouble
без меня это просто Aweso

@CorleyBrigman, можешь ли ты объяснить это подробнее? Я попытался найти документацию по названному тупле или найти то, что я мог бы вызвать на нем, и я не мог понять, как. (Опять же Python не мой самый сильный язык)
Без меня это просто Aweso

2
какая часть? dirэто просто встроенный Python ... вы можете запустить его на любом объекте 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')])

Это документированный метод именованных кортежей, то есть, в отличие от обычного соглашения в 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__свойство, которое присутствовало в именованных кортежах, снова было удалено этим коммитом .


1
Кто-нибудь знает, существует ли прецедент, который предполагает, _asdictчто в стандартной библиотеке не должно быть псевдонимов asdict?
КобеДжон

1
@KobeJohn, тогда ты не мог бы "asdict"быть одним из имен кортежей.
Shadowtalker

28

Там есть встроенный метод на namedtupleслучаях для этого _asdict.

Как обсуждалось в комментариях, на некоторых версиях vars()это тоже будет делать, но, очевидно, это сильно зависит от деталей сборки, тогда как _asdictдолжно быть надежным. В некоторых версиях _asdictбыл помечен как устаревший, но комментарии указывают, что это не относится к 3.4.


1
Я не был downvoter, но это могло быть потому, что _asdictметод был устаревшим в python3 (в пользу vars)
wim

И наоборот, похоже, что varsон не работает в некоторых старых версиях - в 2.7 он вызывает a TypeError, поскольку namedtupleкласс этой версии не имеет __dict__атрибута.
Питер ДеГлоппер

да, Мартейн и я обсуждали это здесь . Он будет работать на более новых версиях 2.7 (я на 2.7.6 и работает)
wim

Прошло окно редактирования моего комментария выше - оно не работает на 2.7.5, поэтому оно должно быть новым с 2.7.6. Разве моя сборка 2.7.5 отключена, как это было у Мартина на связанном ответе? В любом случае, похоже, работает ли он на 2.7.5, зависит от особенностей сборки.
Питер ДеГлоппер

8
Просто наперед: _asdict больше не устарел (и теперь возвращает OrderedDict), и vars выдает ошибку с Python 3.4 (из удаления атрибута dict namedtuples).
Александр Хуссах

2

В версиях python2.7 и python3.4 для Ubuntu 14.04 LTS __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 - это семантический способ получить словарь, представляющий что-то (по крайней мере, насколько мне известно).


Было бы неплохо собрать таблицу основных версий и платформ 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] # покажет «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()

-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. Выделите любое поле для словаря в качестве обязательного индекса для словаря, я использовал «имя».

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.