3

When to use the merge vs update operators on dictionaries.
The following examples, while there are differences in how to call them, their output is the same.

a = {1: 'a', 2: 'b', 3: 'c', 6: 'in both'}
b = {4: 'd', 5: 'e', 6: 'but different'}

Using the update operator

z = a | b    
print(z)

Output: {1: 'a', 2: 'b', 3: 'c', 6: 'but different', 4: 'd', 5: 'e'}

Using The merge operator

a |= b
print(a)

Output: {1: 'a', 2: 'b', 3: 'c', 6: 'but different', 4: 'd', 5: 'e'}

It seems as if the only advantage of the | (merge) is that it doesn't overwrite your old dictionary.
Is there something else that I am missing?
When should I choose to use one over the other?

Pranav Hosangadi
  • 23,755
  • 7
  • 44
  • 70
John Salzman
  • 500
  • 5
  • 14
  • 2
    That's pretty much it. Use `|=` if you don't care about keeping the old dictionary around, `|` otherwise. `|=` might be slightly more efficient, too. Think of it the same way you would of `+` vs. `+=`. – L3viathan Oct 05 '20 at 14:43
  • 1
    You use the new one when you don't want your old dictionary to be overwritten. Same as any other operator versus its assignment equivalent (e.g. `+`, `+=`). The `|` operator is an important addition to 3.9 because previously it was less straightforward to merge two dictionaries without overwriting one of them (you had to hack it with the unpacking operator). – Green Cloak Guy Oct 05 '20 at 14:43
  • 2
    All built-in mutable collections (that I know of) have both `` and `=` variants (where appropriate), where the former creates a copy and the latter happens in place. This is just continuing that pattern. – Carcigenicate Oct 05 '20 at 14:44
  • 1
    Or: https://www.python.org/dev/peps/pep-0584/#specification So yeah, `|` union returns new `dict`. Augmented assignment `|=` is like `update()` on left-hand side. There doesn't seem to be anything else, much more to it. -> The choice would be: in-place or new object? – Ondrej K. Oct 05 '20 at 14:54
  • 1
    My thinking would be "don't use the merge operator", it's just an alias for `dict.update` except it's way less clear that it modifies (rather than just rebind) the LHS in-place. It's the same issue as list's `+=` which modifies the LHS in-place to very odd effect. If you want to update the LHS, just use `dict.update`). – Masklinn Oct 05 '20 at 15:07

1 Answers1

3

The |= operator just updates your original dictionary with the result of the union operation. The | operator returns a new dictionary that is the union of the two dicts. Let's say we have two sets

a = {'hello', 'world', 'abc', 'def'}
b = {'abc', 'ghi', 'jkl'}

The operation a |= b is similar to a = a | b in much the same way as a += b is similar to a = a + b for lists.

a = {'hello', 'world', 'abc', 'def'}
al = list(a)
b = {'abc', 'ghi', 'jkl'}
bl = list(b)

print("Before: ", hex(id(a)), a)
a = a | b
print("After: ", hex(id(a)), a)
# Output: 
# Before:  0x1aa0186f128 {'world', 'def', 'abc', 'hello'}
# After:  0x1aa0186f828 {'world', 'ghi', 'hello', 'jkl', 'def', 'abc'}

print("Before: ", hex(id(al)), al)
al = al + bl
print("After: ", hex(id(al)), al)
# Output: 
# Before:  0x1aa0187a248 ['world', 'def', 'abc', 'hello']
# After:  0x1aa0366bdc8 ['world', 'def', 'abc', 'hello', 'jkl', 'abc', 'ghi']

Evidently, a is now a new set at a different location in memory.

a = {'hello', 'world', 'abc', 'def'}
al = list(a)
b = {'abc', 'ghi', 'jkl'}
bl = list(b)

print("Before", hex(id(a)), a)
a |= b
print("After", hex(id(a)), a)
# Output: 
# Before 0x1aa0186f128 {'world', 'def', 'abc', 'hello'}
# After 0x1aa0186f128 {'world', 'ghi', 'hello', 'jkl', 'def', 'abc'}

print("Before", hex(id(al)), al)
al += bl
print("After", hex(id(al)), al)
# Output:
# Before 0x1aa03646888 ['world', 'def', 'abc', 'hello']
# After 0x1aa03646888 ['world', 'def', 'abc', 'hello', 'jkl', 'abc', 'ghi']

In this case, a is still the old set at a same location in memory, but its contents have been updated.

Pranav Hosangadi
  • 23,755
  • 7
  • 44
  • 70
  • That's really not true: dicts are mutable so it's more like `+=` on *lists*, in that it will modify the LHS dict in-place as if you'd have called `update`. And for the same reasons it's horrible. – Masklinn Oct 05 '20 at 15:05
  • @Carcigenicate Thanks, I've fixed the answer and included more details. – Pranav Hosangadi Oct 05 '20 at 16:15
  • 1
    @PranavHosangadi I didn't downvote, but for one I would say dictionaries are mutable, and the way you are doing it isn't the best way to do it. And people can and will downvote for whatever reason they want. – 10 Rep Oct 05 '20 at 16:26
  • @Carcigenicate Not worried about the downvote, more worried about saying something that's wrong. It looks factually correct to me, maybe somebody took issue with the _"`a|=b` is similar to..."_ sentence *shrug* – Pranav Hosangadi Oct 05 '20 at 16:27
  • @10Rep _"way you are doing it isn't the best way to do it"_ can you elaborate? The point of the answer was to demonstrate that `a |= b` and `a = a | b` give the same result in `a` except that in the first case it happens at the original memory address, but in the second a new set is created at a new location in memory and assigned to the name `a`. – Pranav Hosangadi Oct 05 '20 at 16:31
  • 1
    Thanks @PranavHosangadi for the answer, it clarified what I thought was the difference was. I did some further research and found the only other difference is you can use iterables, but only with the update operator. – John Salzman Oct 05 '20 at 18:26