Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

I try to sum two dictionaries like that:

my_new_dict = dict(my_existing_dict.items() + my_new_dict.items())

but recieve error

TypeError: unsupported operand type(s) for +: 'dict_items' and 'dict_items'

What I do wrong?

like image 977
JohnDow Avatar asked Nov 13 '12 13:11

JohnDow


3 Answers

As of Python 3.9 (PEP 584 in particular), dicts gains union (|) and update (|=) operations just like sets, so that becomes the "one true way" to achieve what you are looking for.

d1 | d2

That PEP lists the other options available in earlier Python versions, which all have their downsides. If you are up to PEP 448 (Python 3.5), I would recommend using:

{**d1, **d2}

This is unpacking both dictionaries into a new one, resulting in a union.

One problem is the behavior you want is ambiguous - dictionaries can't have duplicate keys, so it is unclear what you want to happen if both contain the same key. The spec is explicit about what should happen when using this method:

In dictionaries, later values will always override earlier ones

If you want the reverse behaviour, you can simply swap the order of the dictionaries in the literal.

Your approach doesn't work because dictionary views are set-like, so they don't have addition implemented.

What you probably want is the union: d1.items() | d2.items(), which will give you a set of tuples of (key, value). If you then pass it to dict() and there are duplicates, the "last" value will be the one used, however sets (unlike the views themselves) are unordered, so there is no guarantee about which item will end up "first" in the combined set, meaning that which one "wins" will be arbitrary.

So, in short, as long as order/duplicate selection isn't important:

dict(d1.items() | d2.items())

In Python 2, dict.items() simply returns a list, where your approach will work.

like image 107
Gareth Latty Avatar answered Nov 11 '22 10:11

Gareth Latty


In python3, dict.items() returns an object with type dict_items which apparently can't be added. (in python 2, it returned a list which could be added).

An alternative way to add a pair of dictionaries which works on py2k and py3k:

d = dict1.copy()
d.update(dict2)

Of course, there's some ambiguity about what you want to happen in the case of key collisions. e.g. if both dicts have key1, whose key1 should be preserved in the output? Or should you use some combination of both of their values? In the latter case, you'll probably want something from the collections module (either defaultdict or Counter)

like image 31
mgilson Avatar answered Nov 11 '22 12:11

mgilson


Another approach to the other suggested answers is:

dict(list(d1.items()) + list(d2.items()))

If there are keys present in both d1 and d2, the value in d2 will be used in the final dictionary.

like image 14
erwaman Avatar answered Nov 11 '22 12:11

erwaman