Copy a dictionary, except some keys

How common is the need of getting a copy of a dict, except some of its keys?

It happens to me quite frequently that I need a similar dict to what I have, but without some of its keys. Of course I can’t just remove the keys, as other parts of the code still uses the full dict.

I end up doing stuff like this:

new_dict = {k: v for k, v in old_dict.items() if k not in {'key1', 'key2'}}

What if we could do just…?

new_dict = old_dict.copy(avoid_keys=('key1', 'key2'))  

Alternatives:

new_dict = old_dict.copy(avoid=('key1', 'key2'))  
new_dict = old_dict.copy(except=('key1', 'key2'))  

Thanks!

I don’t know if this is common enough to warrant a method on dict, but I would also consider drop, ignore, and ignore_keys as argument names.

1 Like

You can make your dict comprehension more concise by using the keys() dictionary view:

new_dict = {k: old_dict[k] for k in old_dict.keys() - {'key1', 'key2'}}

These act like sets, so you can use set subtraction.

I agree with Brett that I can’t see this being common enough to complicate the dict.copy() method.

The first version of PEP 584 proposed that dicts could support
the - subtraction operator to do precisely this:

new = d1 - d2

would return a new dict based on a copy of d1 except for the keys of d2.

PEP 584 has currently dropped that operator to concentrate only on dict
addition, but I expect that somebody will propose dicts support the full
set API including subtraction.

I expect this to be really slower, as you’re accesing the old dict for every key! I’ve run both snippets in timeit and this shows a ~33% slowdown.

Of course, yes. I was aiming for conciseness, but it’s not that big an improvement.

I don’t think this is common enough to warrant adding a method or extending the abilities of an existing method of dict.

I can recommend the funcy module for good, well-tested implementations of many such basic operations (not only for dicts). For this case, funcy.omit() does exactly what you want:

funcy.omit(old_dict, 'key1', 'key2')

How odd.

I would have taken the existence of funcy.omit as evidence that this
requested feature is common enough to warrant adding a method, rather
than the opposite.

This is the way I see it: The funcy library has over a hundred such helpers. If we added many or all of them to Python’s built-ins and stdlib, IMO we’d be doing the language a disservice by increasing the number of basics anyone has to learn to read and maintain Python code. On the other hand, for a specific codebase, deciding to use funcy consistently can be beneficial; I’ve seen this done with good results.

3 Likes