在这种复杂的情况下如何写字典理解?
How to write dictionary comprehension in this complicated case?
一个例子是人为的,但我遇到过很多次类似的问题。
db_file_names = ['f1', 'f2'] # list of database files
def make_report(filename):
# read the database and prepare some report object
return report_object
现在我想构造一个字典:db_version -> number_of_tables。报告对象包含我需要的所有信息。
字典理解可能如下所示:
d = {
make_report(filename).db_version: make_report(filename).num_tables
for filename in db_file_names
}
这种方法有时有效,但效率很低:为每个数据库准备两次报告。
为了避免这种低效率,我通常使用以下方法之一:
使用临时存储:
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()}
但通常是在我写了一些错误的理解之后,想一想,在这种情况下是不可能做到干净简单的理解的。
问题是,在这种情况下是否有更好的方法来创建所需的字典?
从昨天开始(当我决定 post 这个问题时)我又发明了一种方法,我比其他方法更喜欢它:
d = {
report.db_version: report.num_tables
for filename in db_file_names
for report in [make_report(filename), ]
}
不过就连这个也不太好看
您可以使用:
d = {
r.db_version: r.num_tables
for r in map(make_report, db_file_names)
}
注意在Python3中,map
给出了一个迭代器,因此没有不必要的存储开销。
这是一个实用的方法:
from operator import attrgetter
res = dict(map(attrgetter('db_version', 'num_tables'),
map(make_report, db_file_names)))
不幸的是,功能组合不是标准库的一部分,但第 3 方 toolz
确实提供了此功能:
from toolz import compose
foo = compose(attrgetter('db_version', 'num_tables'), make_report)
res = dict(map(foo, db_file_names))
从概念上讲,您可以认为这些函数式解决方案输出元组的可迭代对象,然后可以将其直接馈送到 dict
.
一个例子是人为的,但我遇到过很多次类似的问题。
db_file_names = ['f1', 'f2'] # list of database files
def make_report(filename):
# read the database and prepare some report object
return report_object
现在我想构造一个字典:db_version -> number_of_tables。报告对象包含我需要的所有信息。
字典理解可能如下所示:
d = {
make_report(filename).db_version: make_report(filename).num_tables
for filename in db_file_names
}
这种方法有时有效,但效率很低:为每个数据库准备两次报告。
为了避免这种低效率,我通常使用以下方法之一:
使用临时存储:
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()}
但通常是在我写了一些错误的理解之后,想一想,在这种情况下是不可能做到干净简单的理解的。
问题是,在这种情况下是否有更好的方法来创建所需的字典?
从昨天开始(当我决定 post 这个问题时)我又发明了一种方法,我比其他方法更喜欢它:
d = {
report.db_version: report.num_tables
for filename in db_file_names
for report in [make_report(filename), ]
}
不过就连这个也不太好看
您可以使用:
d = {
r.db_version: r.num_tables
for r in map(make_report, db_file_names)
}
注意在Python3中,map
给出了一个迭代器,因此没有不必要的存储开销。
这是一个实用的方法:
from operator import attrgetter
res = dict(map(attrgetter('db_version', 'num_tables'),
map(make_report, db_file_names)))
不幸的是,功能组合不是标准库的一部分,但第 3 方 toolz
确实提供了此功能:
from toolz import compose
foo = compose(attrgetter('db_version', 'num_tables'), make_report)
res = dict(map(foo, db_file_names))
从概念上讲,您可以认为这些函数式解决方案输出元组的可迭代对象,然后可以将其直接馈送到 dict
.