如何在这个复杂的案例中写字典理解?

时间:2018-05-10 13:00:19

标签: python dictionary list-comprehension dictionary-comprehension

一个例子是人为的,但我有很多次类似的问题。

d = {
    make_report(filename).db_version: make_report(filename).num_tables
    for filename in db_file_names
}

现在我要构建一个字典:db_version - > number_of_tables。报告对象包含我需要的所有信息。

字典理解可能如下:

reports = [make_report(filename) for filename in db_file_names]
d = {r.db_version: r.num_tables for r in reports}

这种方法有时会起作用,但效率很低:报告为每个数据库准备两次。

为了避免这种低效率,我通常使用以下方法之一:

使用临时存储:

def gen_data():
    for filename in db_file_names:
        report = make_report(filename)
        yield report.db_version, report.num_tables

d = {dat[0]: dat[1] for dat in gen_data()}

或者使用一些适配器生成器:

d = {
    report.db_version: report.num_tables
    for filename in db_file_names
    for report in [make_report(filename), ]
}

但通常只有在我写了一些错误的理解之后,才能思考并意识到,在这种情况下,干净而简单的理解是不可能的。

问题是,在这种情况下是否有更好的方法来创建所需的字典?

从昨天开始(当我决定发布这个问题时)我发明了另外一种方法,我更喜欢其他方法:

password_changed_date

但即使这个看起来也不是很好。

2 个答案:

答案 0 :(得分:3)

您可以使用:

d = {
    r.db_version: r.num_tables
    for r in map(make_report, db_file_names)
}

请注意,在Python 3中,map提供了一个迭代器,因此没有不必要的存储成本。

答案 1 :(得分:0)

这是一种功能性的方式:

from operator import attrgetter

res = dict(map(attrgetter('db_version', 'num_tables'),
               map(make_report, db_file_names)))

不幸的是,功能组合不是标准库的一部分,但第三方toolz确实提供了此功能:

from toolz import compose

foo = compose(attrgetter('db_version', 'num_tables'), make_report)
res = dict(map(foo, db_file_names))

从概念上讲,您可以考虑输出可迭代元组的这些函数解决方案,然后可以直接将其提供给dict