12

From the python documentation I see that dict has an update(...) method, but it appears it does not take exceptions where I may not want to update the old dictionary with a new value. For instance, when the value is None.

This is what I currently do:

for key in new_dict.keys():
  new_value = new_dict.get(key)
  if new_value: old_dict[key] = new_value

Is there a better way to update the old dictionary using the new dictionary.

Vaibhav Bajpai
  • 16,374
  • 13
  • 54
  • 85
  • 1
    Your code also discards `False` and `0`. You can also iterate using `for k,v in new_dict.items():` – t-8ch Mar 07 '13 at 17:13

4 Answers4

18

You could use something like:

old = {1: 'one', 2: 'two'}
new = {1: 'newone', 2: None, 3: 'new'}

old.update( (k,v) for k,v in new.items() if v is not None)

# {1: 'newone', 2: 'two', 3: 'new'}
betontalpfa
  • 3,454
  • 1
  • 33
  • 65
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
1

Update: I think I was trying to answer the wrong question here (see my comment below), since this clearly does not answer the question being asked. In case there is something useful, I'll leave this here anyway (unless someone makes it clear that it would be better to just delete it).

Building on Jon's answer but using set intersection as suggested here:

In python 3:

old.update((k, new[k]) for k in old.keys() & new.keys())

In python 2.7:

old.update((k, new[k]) for k in old.viewkeys() & new.viewkeys())

In python 2.7 or 3 using the future package:

from future.utils import viewkeys
old.update((k, new[k]) for k in viewkeys(old) & viewkeys(new))

Or in python 2 or 3 by without the future package by creating new sets:

old.update((k, new[k]) for k in set(old.keys()) & set(new.keys()))
teichert
  • 3,963
  • 1
  • 31
  • 37
  • 1
    In practice this looks nice, but `update()` already only updates keys that are present in `new`. However, it doesn't answer the question where values are `None` and skipping those keys. – Sunny Patel Sep 15 '20 at 00:06
  • 1
    @SunnyPatel You're right! In fact, now that I look again at this, I see that my solution would also fail to update values for keys that weren't present in `old`. In fact, I think I must have been trying to answer the wrong question: "How do I (efficiently) only update values for keys that were already present in `old`?" For that question, the timings in [this solution](https://stackoverflow.com/a/36280797/3780389) show how the intersection can actually be helpful for performance even if unnecessary for correctness. (thanks!) – teichert Sep 18 '20 at 04:57
0

For python 3.x to iterate throughout dictionary key values use for k,v in new.items()

IN: 
old = {1: 'one', 2: 'two'}
new = {1: 'new_one', 2: None, 3: 'new_three'}

old.update((k,v) for k,v in new.items() if v is not None)

Out:
old = {1: 'new_one', 2: 'two'}
Aidar Gatin
  • 755
  • 1
  • 7
  • 9
0

If you get here from a pydantic object that you created into dict, this wont work. Instead use pydantic function dict(exclude_none). Python 3.7+ For example,

     existing_job = db.query(MedicalRecord).filter(MedicalRecord.id == id)
else:
    existing_job = db.query(MedicalRecord).filter(MedicalRecord.id == id, MedicalRecord.owner_id==user.id)
if not existing_job.first():
    return 0
job.directory_hash = None



#doesnt work:
existing_job.update((k,v) for k,v in job.dict().items() if v is not None)
job = job.dict(exclude_none=True)
existing_job.update(job) # works