将一个命名元组转换为字典。

232

我在Python中有一个命名元组类

class Town(collections.namedtuple('Town', [
    'name', 
    'population',
    'coordinates',
    'population', 
    'capital', 
    'state_bird'])):
    # ...
我想将Town实例转换为字典。我不希望它刚好与Town中字段的名称或数量相关联。
是否可以编写代码以便添加更多字段,或者传递一个完全不同的命名元组并获得一个字典呢?
由于原始类定义位于其他人的代码中,因此我无法更改它。所以我需要将Town的实例转换为字典。

3
顺便说一句...看看Tab自动补全或者dir命令,它们会显示任何对象的字段...这将直接显示_asdict函数。 - Corley Brigman
看起来你真正想做的是从dict子类化而不是'namedtuple',并将命名元组传递到初始化程序中。请记住,如果你习惯于Cxx,class Town(x)不是构造函数,它里面的def __init__(self, *args, **kwargs)才是。 - Corley Brigman
我无法更改原始类,因为它在别人的代码中。所以我必须从namedtouble进行子类化。 - Without Me It Just Aweso
@CorleyBrigman 你能更详细地解释一下吗?我试图找到关于命名元组的文档,或者找出可以调用它的内容,但我无法弄清楚。 (再次说明Python不是我最擅长的语言) - Without Me It Just Aweso
2
哪个部分?dir只是Python内置的一个函数...你可以在控制台或脚本中运行它(它会返回一个列表,你可以打印或进行其他操作),并且它将返回对象的(几乎)所有属性的列表。如果你试图弄清楚一个未知对象的工作原理,这非常有帮助。 - Corley Brigman
显示剩余2条评论
6个回答

407

简而言之:有一个名为_asdict的方法可供使用。

以下是用法示例:

>>> from collections import namedtuple
>>> fields = ['name', 'population', 'coordinates', 'capital', 'state_bird']
>>> Town = namedtuple('Town', fields)
>>> funkytown = Town('funky', 300, 'somewhere', 'lipps', 'chicken')
>>> funkytown._asdict()
{'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__属性再次被此提交移除。

2
有没有人知道是否已经有一个先例表明在标准库中将 _asdict 别名为 asdict 是不应该的? - KobeJohn
5
那么您不能将“asdict”作为元组名称之一。 - shadowtalker
真让人恼火!vars是自然、惯用的方法!难道它不能将namedtuple作为特殊情况处理吗?在我看来,这并不像是太难的事情。 - robert
@robert vars(obj)应该等同于obj.__dict__,因此特殊情况将改变vars的记录行为(元组实例不会携带__dict__)。 - wim
是的,我理解你的借口,但这对我没有任何说服力。你所描述的是它的实现方式,而“vars”则“隐藏”了该实现(用面向对象的术语来说)。我猜他们可能有一个“好”的理由不能简单地重载该方法,但在我看来,这似乎是标准上的一个失误。 - robert
从3.8版本开始,_asdict()返回一个dict而不是OrderedDict,因为从3.7版本开始,dict是有序的。请参见https://docs.python.org/3/library/collections.html#collections.namedtuple - Marc Meketon

35

有一个内置方法可以在namedtuple实例上使用,名为_asdict

正如评论中所讨论的,某些版本上也可以使用vars()来完成此操作,但这显然高度依赖于构建细节,而_asdict应该是可靠的。在一些版本中,_asdict被标记为已弃用,但评论表明,从3.4版本开始情况并非如此。


1
我不是那个给你点踩的人,但可能是因为 _asdict 方法已经在 Python3 中被废弃(推荐使用 vars) 。详情请见:https://docs.python.org/3/library/collections.html#collections.somenamedtuple._asdict - wim
是的,Martijn和我已经在这里讨论过了:http://stackoverflow.com/a/19840533/674039。顺便说一句,它适用于更新版本的2.7(我用的是2.7.6,它可以运行)。 - wim
8
提醒一下:_asdict不再被弃用(现在返回OrderedDict),而vars在Python 3.4中会产生错误(因为namedtuples的__dict__属性被删除了)。 - Alex Huszagh
@AlexanderHuszagh - 谢谢,已经更新了答案并加入了这个信息。看起来 _asdict 是最一致的方法,即使在某些版本中它已被弃用。 - Peter DeGlopper
1
我无法跟踪vars()显然经常变化的状态。欢迎提出其他准确描述它的建议。 - Peter DeGlopper
显示剩余7条评论

8

通常 _asdict() 返回一个有序字典OrderedDict。这是如何将有序字典OrderedDict转换为普通字典dict的方法:


town = Town('funky', 300, 'somewhere', 'lipps', 'chicken')
dict(town._asdict())

输出结果将为:
{'capital': 'lipps',
 'coordinates': 'somewhere',
 'name': 'funky',
 'population': 300,
 'state_bird': 'chicken'}

3
这已经不再是必需的了。自 Python 3.8 起,_asdict() 返回一个 dict 而不是 OrderedDict - Marc Meketon

3
在Ubuntu 14.04 LTS版本的python2.7和python3.4中,__dict__属性按预期工作。_asdict 方法也可以正常使用,但我更倾向于使用标准定义的统一属性API而不是本地化的非统一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

由我所知,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] # 将显示“后端程序员”

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()

-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}

不太有用,因为你知道名称已经在那里了。应该使用盲方法。 - Mitchell Currie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接