Return copy of dictionary excluding specified keys

Question:

I want to make a function that returns a copy of a dictionary excluding keys specified in a list.

Considering this dictionary:

my_dict = {
    "keyA": 1,
    "keyB": 2,
    "keyC": 3
}

A call to without_keys(my_dict, ['keyB', 'keyC']) should return:

{
    "keyA": 1
}

I would like to do this in a one-line with a neat dictionary comprehension but I’m having trouble. My attempt is this:

def without_keys(d, keys):
    return {k: d[f] if k not in keys for f in d}

which is invalid syntax. How can I do this?

Asked By: Juicy

||

Answers:

You were close, try the snippet below:

>>> my_dict = {
...     "keyA": 1,
...     "keyB": 2,
...     "keyC": 3
... }
>>> invalid = {"keyA", "keyB"}
>>> def without_keys(d, keys):
...     return {x: d[x] for x in d if x not in keys}
>>> without_keys(my_dict, invalid)
{'keyC': 3}

Basically, the if k not in keys will go at the end of the dict comprehension in the above case.

Answered By: Anshul Goyal

This should work for you.

def without_keys(d, keys):
    return {k: v for k, v in d.items() if k not in keys}
Answered By: Morgan Thrapp

In your dictionary comprehension you should be iterating over your dictionary (not k , not sure what that is either). Example –

return {k:v for k,v in d.items() if k not in keys}
Answered By: Anand S Kumar

For those who don’t like list comprehensions, this is my version:

def without_keys(d, *keys):
     return dict(filter(lambda key_value: key_value[0] not in keys, d.items()))

Usage:

>>> d={1:3, 5:7, 9:11, 13:15}
>>> without_keys(d, 1, 5, 9)
{13: 15}
>>> without_keys(d, 13)
{1: 3, 5: 7, 9: 11}
>>> without_keys(d, *[5, 7])
{1: 3, 13: 15, 9: 11}
Answered By: Himel Das

Even shorter. Apparently python 3 lets you ‘subtract’ a list from a dict_keys.

def without_keys(d, keys):
    return {k: d[k] for k in d.keys() - keys}
Answered By: Mike Fogel

You could this generalized for nested dictionaries solution

def copy_dict(data, strip_values=False, remove_keys=[]):
    if type(data) is dict:
        out = {}
        for key, value in data.items():
            if key not in remove_keys:
                out[key] = copy_dict(value, strip_values=strip_values, remove_keys=remove_keys)
        return out
    else:
        return [] if strip_values else data

This recursive solution works for nested dictionaries and removes keys not required from the entire nested structure. It also gives you the ability to return the nest with only keys and no values.

Answered By: Rakshit Kothari

Your oneliner

my_dict = {"keyA": 1, "keyB": 2, "keyC": 3}
(lambda keyB, keyC, **kw: kw)(**my_dict)

which returns {'keyA': 1}.
Not very pythonic and dynamic, but hacky and short.
It uses the dict unpacking (destructuring assignment) of function arguments.

See also
https://stackoverflow.com/a/53851069/11769765.

Answered By: Friedrich