如何从字典生成器中合并多个字典以创建单一的汇总Python字典
我在寻求帮助,希望能用更Pythonic的方式来做这件事。
这是我目前的代码。
我创建了一个生成器,用来生成一个字典,字典的键是一个元组,值是我在项目中想要使用的对象。
我相信有更好的方法来实现这个目标。我尝试用字典和列表推导式,但都没有成功。
app = models.get_app('djangoapp')
appmodels = models.get_models(app)
gen = mapEntGen(appmodels)
d = {}
for x in gen:
d.update(x)
为了让大家更清楚我的对象是什么样的。
for x in gen:
print(x)
{('in', 1): <class 'djangoapp.models.entrance01IN'>}
{('out', 1): <class 'djangoapp.models.entrance01OUT'>}
{('in', 2): <class 'djangoapp.models.entrance02IN'>}
{('out', 2): <class 'djangoapp.models.entrance02OUT'>}
...
这是我尝试使用推导式的失败例子。
{d: aDict for aDict in mapEntGen(appmodels)}
d = {key: value for (key, value) in gen}
d = {key: value for (key, value) in mapEntGen(appmodels[1:])}
我认为问题很可能是因为我已经在使用一个字典,而不是其他两种类型。字典可以用作键值对。
----> 1 for k, v in gen:
2 d[k] = v
3
ValueError: need more than 1 value to unpack
这是我用来生成对象映射和查找键的另一个代码。
def mapEntGen(EntranceObj = []):
for x in EntranceObj:
thisEnt = (x._meta.verbose_name[10:],
int(x._meta.verbose_name[8:10]))
aDict = {thisEnt : x}
yield aDict
这可能看起来像是重复的问题,但我尝试的所有例子都没有成功。
2 个回答
解决你问题的最简单方法就是不使用mapEntGen,直接这样做:
d = {((x._meta.verbose_name[10:],
int(x._meta.verbose_name[8:10])):x
for x in EntranceObj}
这样就不需要创建不同的字典再把它们合在一起了。
如果你想用生成器的话,为什么要让它返回一个字典呢?而这个字典里只有一个键值对?不如让它返回一个元组:
def mapEntGen(EntranceObj = []):
for x in EntranceObj:
thisEnt = (x._meta.verbose_name[10:],
int(x._meta.verbose_name[8:10]))
yield (thisEnt, x)
这样获取d
就简单多了:
d = dict(mapEntGen(appmodels))
如果你想用你自己的生成器:
mapEntGen(appmodels)
会生成字典,直接把它当成字典来用就行。当你想遍历它们的内容时,需要调用iteritems,然后进行遍历。这样应该可以:
d = {key:value for subdct in gen for key, value in subdct.iteritems()}
为了确保你理解这个表达式,它其实等同于这样做:
d = {}
for subdct in gen:
for key, value in subdct.iteritems():
d[key] = value
(当然gen
可以用mapEntGen(appmodels)
替代)
为了让你的代码更清晰易懂,我想给你一个完全不同的方向,可能会更好用,具体要看你其他代码的情况:
我们不再使用mapGenEnt,而是从appModels(不管那是什么)创建两个独立的生成器:
- 一个是代码的列表(你之后会把它当作键,比如
('out', 1)
)。 - 另一个是实际的对象或模型的列表(你之后会把它当作值,比如
<class 'djangoapp.models.entrance01IN'>
)。
假设你有这两个生成器:
def code_names(EntranceObj):
return ((entrance._meta.verbose_name[10:], int(entrance._meta.verbose_name[8:10]) for entrance in EntranceObj)
def entries(EntranceObj):
return EntranceObj # Shorter than: (entrance for entrance in EntranceObj)
现在我们有两个函数,各自做自己的事情,我们还需要创建 d
。这很简单,可以使用 zip
或 itertools.izip
:
d = dict(zip(code_names(appmodels), entries(appmodels)))
为了让代码更易读,我个人建议给这个函数起个名字,比如 generate_model_entries(appmodels)
:
def generate_model_entries(models):
return dict(zip(code_names(models), entries(models)))
d = generate_model_entries(appmodels)
PS:如果你能给循环变量起个比 x
更准确的名字,请务必使用。