To remove multiple keys from a dictionary in Python, loop over the keys and call d.pop(key, None) for each one. The None default means missing keys are skipped instead of raising KeyError. To keep the original intact, build a new dict with a comprehension:
for key in ("ssn_last4", "card_token"):
customer.pop(key, None)
The examples strip private fields from US customer and order records, and I ran them all with Python 3.12.5.
You’ll see the pop loop, why del can stop halfway, building a filtered copy, removing keys by value without a RuntimeError, cleaning nested data, and which method is quickest.
Remove multiple keys with pop() in a loop
pop(key, default) removes the key and returns its value, or returns the default if the key isn’t there. That makes it safe for keys that may or may not exist:
customer = {"id": 1042, "name": "Emily Carter", "email": "emily@example.com",
"ssn_last4": "1234", "card_token": "tok_9f2", "city": "Austin"}
for key in ("ssn_last4", "card_token", "phone"): # "phone" isn't there - no error
customer.pop(key, None)
print(customer)
removed = {k: customer.pop(k) for k in ("email",) if k in customer}
print("removed:", removed, "| keys left:", list(customer))
Output:
{'id': 1042, 'name': 'Emily Carter', 'email': 'emily@example.com', 'city': 'Austin'}
removed: {'email': 'emily@example.com'} | keys left: ['id', 'name', 'city']

The second part keeps what you removed, which is useful for logging. For the single-key version of this, see removing a key without an error.
Why does del stop halfway through?
del d[key] raises KeyError on the first missing key, and the keys after it are never removed:
customer = {"id": 1042, "name": "Emily Carter", "ssn_last4": "1234", "city": "Austin"}
try:
for key in ("ssn_last4", "phone", "city"):
del customer[key]
except KeyError as err:
print("KeyError:", err)
print(customer) # ssn_last4 is gone, city is still here
Output:
KeyError: 'phone'
{'id': 1042, 'name': 'Emily Carter', 'city': 'Austin'}
Here city survives because the loop stopped at phone. Use pop(key, None), or check if key in d first. The error itself is explained in Python dictionary KeyError.
Remove keys by building a new dictionary
When you shouldn’t change the original, say it’s shared or cached, filter into a new dict. Keys views also support set operations:
order = {"id": 2041, "total": 129.99, "card_token": "tok_9f2", "internal_note": "VIP", "state": "TX"}
private = {"card_token", "internal_note"}
public = {k: v for k, v in order.items() if k not in private}
print(public)
keep = order.keys() - private # set difference on the keys view
print(sorted(keep))
print("original still has", len(order), "keys")
Output:
{'id': 2041, 'total': 129.99, 'state': 'TX'}
['id', 'state', 'total']
original still has 5 keys

Put the keys to drop in a set so each in check is fast. This copy approach is covered in more depth in copying a dictionary without some of its keys.
How do I remove keys while iterating over a dictionary?
You can’t change a dict’s size while looping over it. Python raises a RuntimeError. Loop over a copy of the keys instead:
prices = {"Mug": 12.0, "Filters": 0.0, "Beans": 18.5, "Kettle": 0.0}
try:
for item in prices:
if prices[item] == 0.0:
del prices[item]
except RuntimeError as err:
print("RuntimeError:", err)
prices = {"Mug": 12.0, "Filters": 0.0, "Beans": 18.5, "Kettle": 0.0}
for item in list(prices): # iterate over a copy of the keys
if prices[item] == 0.0:
del prices[item]
print(prices)
Output:
RuntimeError: dictionary changed size during iteration
{'Mug': 12.0, 'Beans': 18.5}

list(prices) takes a snapshot of the keys, so deleting is safe. To drop keys whose values are empty, see removing empty keys from a dictionary.
Remove keys from a nested dictionary
API responses nest dicts inside lists inside dicts. A small recursive function removes the keys at every level and returns a clean copy:
import json
def drop_keys(data, keys):
"""Return a copy of data with the keys removed at every level."""
if isinstance(data, dict):
return {k: drop_keys(v, keys) for k, v in data.items() if k not in keys}
if isinstance(data, list):
return [drop_keys(item, keys) for item in data]
return data
response = {"user": {"name": "James Wilson", "password_hash": "x91", "token": "abc"},
"orders": [{"id": 1, "total": 54.5, "token": "t1"}, {"id": 2, "total": 230.25, "token": "t2"}],
"token": "top"}
print(json.dumps(drop_keys(response, {"token", "password_hash"}), indent=2))
Output:
{
"user": {
"name": "James Wilson"
},
"orders": [
{
"id": 1,
"total": 54.5
},
{
"id": 2,
"total": 230.25
}
]
}

I use this before logging API data. For deeper KeyError problems in nested data, see KeyError in a nested Python dictionary.
Which way to remove multiple keys is fastest?
Here are 5,000 keys removed from a 10,000-key dict, best of three runs. The two in-place versions include the cost of copying the dict first:
import timeit
setup = "d0 = {f'k{i}': i for i in range(10_000)}; drop = {f'k{i}' for i in range(0, 10_000, 2)}"
tests = {
"pop loop (in place)": "d = d0.copy()\nfor k in drop: d.pop(k, None)",
"comprehension (new)": "d = {k: v for k, v in d0.items() if k not in drop}",
"del with check": "d = d0.copy()\nfor k in drop:\n if k in d: del d[k]",
}
for label, stmt in tests.items():
t = min(timeit.repeat(stmt, setup, number=200, repeat=3))
print(f"{label:<22} {t / 200 * 1000:.3f} ms per run (5,000 of 10,000 keys)")
Output:
pop loop (in place) 0.419 ms per run (5,000 of 10,000 keys)
comprehension (new) 0.474 ms per run (5,000 of 10,000 keys)
del with check 0.496 ms per run (5,000 of 10,000 keys)
The numbers are all small, so pick by intent: in place or a new dict. Counting what’s left is shown in counting the keys in a dictionary.
Ways to remove multiple keys compared
| Method | Changes original? | Missing key |
|---|---|---|
for k in keys: d.pop(k, None) | Yes | Ignored |
for k in keys: del d[k] | Yes | KeyError, stops |
{k: v for k, v in d.items() if k not in keys} | No | Ignored |
d.keys() - keys | No (gives a set) | Ignored |
for k in list(d): ... | Yes | Removes by condition |
A few more dictionary guides you might find useful:
- Remove an item from a dictionary in Python
- Change a key in a Python dictionary
- Get the keys of a dictionary in Python
- Remove duplicate values from a dictionary
Frequently asked questions
How do I remove multiple keys from a dictionary in Python?
Loop over the keys and call d.pop(key, None) on each, or build a new dict with a comprehension.
How do I remove keys without a KeyError?
Use pop(key, None). The default is returned when the key is missing.
Can I delete keys while looping over a dictionary?
Not directly: you get RuntimeError: dictionary changed size during iteration. Loop over list(d) instead.
How do I keep the original dictionary unchanged?
Use {k: v for k, v in d.items() if k not in drop}, which returns a new dict.
How do I remove a key from nested dictionaries?
Use a recursive function that rebuilds dicts and lists without the unwanted keys.
Where is dict.pop documented?
See dict.pop() in the Python docs.

Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn