python – multiple key value pairs in dict comprehension

python – multiple key value pairs in dict comprehension

A dictionary comprehension can only ever produce one key-value pair per iteration. The trick then is to produce an extra loop to separate out the pairs:

{k: v for e in wp_users for k, v in zip((ID, post_author), e)}

This is equivalent to:

result = {}
for e in wp_users:
    for k, v in zip((ID, post_author), e):
        result[k] = v

Note that this just repeats the two keys with each of your wp_users list, so you are continually replacing the same keys with new values! You may as well just take the last entry in that case:

result = dict(zip((ID, post_author), wp_users[-1]))

You didn’t share what output you expected however.

If the idea was to have a list of dictionaries, each with two keys, then you want a list comprehension of the above expression applied to each wp_users entry:

result = [dict(zip((ID, post_author), e)) for e in wp_users]

That produces the same output as your own, second attempt, but now you have a list of dictionaries. You’ll have to use integer indices to get to one of the dictionaries objects or use further loops.

I came across this old question by accident, and Im not convinced by the accepted answer.

Accepted answer

What is disturbing with the accepted answer? Consider this:

>>> wp_users = [(1, Bill), (2, Bob)]
>>> {k: v for e in wp_users for k, v in zip((ID, post_author), e)}
{ID: 2, post_author: Bob}
  • First iteration over wp_users, e = (1, Bill), the dict is {ID:1, post_author: Bill}
  • Second iteration over wp_users, e = (2, Bob), the dict is totally overwritten to {ID:2, post_author: Bob}

On every iteration, all the values of the dictonary are overwritten. You can avoid a loop and jump directly to the last element of wp_users:

>>> {k: v for e in wp_users for k, v in zip((ID, post_author), e)}
{ID: 2, post_author: Bob}


>>> dict(zip((ID, post_author), wp_users[-1]))
{ID: 2, post_author: Bob}

I think thats not what you want.

What you are trying to achieve remains unclear, but I see two options: you have a list of users (id, post_author) and you want to create either a list of dictionaries (one dict per user) or a dictionary of tuples (one tuple per field). You can see the first version as a presentation by lines, and the second as a presentation by columns of the same data.

A list of dictionaries

Try this:

>>> [dict(zip((ID, post_author), user)) for user in wp_users]
[{ID: 1, post_author: Bill}, {ID: 2, post_author: Bob}]

For each user, zip will create tuples (ID, id) and (post_author, author) and dict will generate the dictionaries. Now you can access to the fields like that:

>>> ds = [dict(zip((ID, post_author), user)) for user in wp_users]
>>> ds[0][post_author]

A dictionary of tuples

Thats more unusual, but you might want one dictionary whose values are tuples:

>>> dict(zip((ID, post_author), zip(*wp_users)))
{ID: (1, 2), post_author: (Bill, Bob)}

zip(*wp_users) simply creates a list of tuples [(id1, id2, ...), (post_author1, post_author2, ...)] and the rest is similar to the previous version.

>>> d = dict(zip((ID, post_author), zip(*wp_users)))
>>> d[post_author][0]


To extract a column from the line view:

>>> [d[ID] for d in ds]
[1, 2]

To extract a line from the column view:

>>> {k:vs[1] for k, vs in d.items()}
{ID: 2, post_author: Bob}

python – multiple key value pairs in dict comprehension

I think your problem is that the second version is creating a list of dictionaries, not just one dictionary. You are trying to access a list with a string, which raises the error:

>>> obj = [{data1: 67, data2: 78}]
>>> obj[0][data1]
>>> obj[data1]
Traceback (most recent call last):
  File <stdin>, line 1, in <module>
TypeError: list indices must be integers, not str

Instead, just access the second version as `wp_list[0][post_author], and it should work fine:

>>> wp_users = (Bob, Joe, Sally)
>>> wp_list = [{ID: (e[0]), post_author: (e[1])} for e in wp_users]
>>> wp_list[0][post_author]
>>> wp_list[1][post_author]
>>> wp_list[2][post_author]

Leave a Reply

Your email address will not be published. Required fields are marked *