# What does |= (ior) do in Python?

## What does |= (ior) do in Python?

`|=`

performs an *in-place*^{+} operation between pairs of objects. In particular, between:

- sets: a union operation
- dicts: an update operation
- counters: a union (of multisets) operation
- numbers: a bitwise OR, binary operation

In most cases, it is related to the `|`

operator. See examples below.

**Sets**

For example, the union of two assigned sets `s1`

and `s2`

share the following equivalent expressions:

```
>>> s1 = s1 | s2 # 1
>>> s1 |= s2 # 2
>>> s1.__ior__(s2) # 3
```

where the final value of `s1`

is equivalent either by:

- an assigned OR operation
- an in-place OR operation
- an in-place OR operation via special method
^{++}

*Example*

Here we apply OR (`|`

) and the in-place OR (`|=`

) to *sets*:

```
>>> s1 = {a, b, c}
>>> s2 = {d, e, f}
>>> # OR, |
>>> s1 | s2
{a, b, c, d, e, f}
>>> s1 # `s1` is unchanged
{a, b, c}
>>> # In-place OR, |=
>>> s1 |= s2
>>> s1 # `s1` is reassigned
{a, b, c, d, e, f}
```

**Dictionaries**

In Python 3.9+, new merge (`|`

) and update (`|=`

) operators are proposed between dictionaries. Note: these are not the same as set operators mentioned above.

Given operations between two assigned dicts `d1`

and `d2`

:

```
>>> d1 = d1 | d2 # 1
>>> d1 |= d2 # 2
```

where `d1`

is equivalent via:

- an assigned merge-right operation
- an in-place merge-right (update) operation; equivalent to
`d1.update(d2)`

*Example*

Here we apply merge (`|`

) and update (`|=`

) to *dicts*:

```
>>> d1 = {a: 0, b: 1, c: 2}
>>> d2 = {c: 20, d: 30}
>>> # Merge, |
>>> d1 | d2
{a: 0, b: 1, c: 20, d: 30}
>>> d1
{a: 0, b: 1, c: 2}
>>> # Update, |=
>>> d1 |= d2
>>> d1
{a: 0, b: 1, c: 20, d: 30}
```

**Counters**

The `collections.Counter`

is related to a mathematical datastructure called a *multiset* (mset). It is basically a dict of (object, multiplicity) key-value pairs.

Given operations between two assigned counters `c1`

and `c2`

:

```
>>> c1 = c1 | c2 # 1
>>> c1 |= c2 # 2
```

where `c1`

is equivalent via:

- an assigned union operation
- an in-place union operation

A union of multisets contains the maximum multiplicities per entry. Note, this does not behave the same way as between two sets or between two regular dicts.

*Example*

Here we apply union (`|`

) and the in-place union (`|=`

) to *Counters*:

```
import collections as ct
>>> c1 = ct.Counter({2: 2, 3: 3})
>>> c2 = ct.Counter({1: 1, 3: 5})
>>> # Union, |
>>> c1 | c2
Counter({2: 2, 3: 5, 1: 1})
>>> c1
Counter({2: 2, 3: 3})
>>> # In-place Union, |=
>>> c1 |= c2
>>> c1
Counter({2: 2, 3: 5, 1: 1})
```

**Numbers**

Lastly, you can do binary math.

Given operations between two assigned numbers `n1`

and `n2`

:

```
>>> n1 = n1 | n2 # 1
>>> n1 |= n2 # 2
```

where `n1`

is equivalent via:

- an assigned bitwise OR operation
- an in-place bitwise OR operation

*Example*

Here we apply bitwise OR (`|`

) and the in-place bitwise OR (`|=`

) to *numbers*:

```
>>> n1 = 0
>>> n2 = 1
>>> # Bitwise OR, |
>>> n1 | n2
1
>>> n1
0
>>> # In-place Bitwise OR, |=
>>> n1 |= n2
>>> n1
1
```

**Review**

This section briefly reviews some bitwise math. In the simplest case, the bitwise OR operation compares two binary bits. It will always return `1`

except when both bits are `0`

.

```
>>> assert 1 == (1 | 1) == (1 | 0) == (0 | 1)
>>> assert 0 == (0 | 0)
```

We now extend this idea beyond binary numbers. Given any two integral numbers (lacking fractional components), we apply the bitwise OR and get an integral result:

```
>>> a = 10
>>> b = 16
>>> a | b
26
```

How? In general, the bitwise operations follow some rules:

- internally compare binary equivalents
- apply the operation
- return the result as the given type

Lets apply these rules to our regular integers above.

(1) Compare binary equivalents, seen here as strings (`0b`

denotes binary):

```
>>> bin(a)
0b1010
>>> bin(b)
0b10000
```

(2) Apply a bitwise OR operation to each column (`0`

when both are `0`

, else `1`

):

```
01010
10000
-----
11010
```

(3) Return the result in the given type, e.g. base 10, decimal:

```
>>> int(0b11010)
26
```

The internal binary comparison means we can apply the latter to integers in any base, e.g. hex and octal:

```
>>> a = 10 # 10, dec
>>> b = 0b10000 # 16, bin
>>> c = 0xa # 10, hex
>>> d = 0o20 # 16, oct
>>> a | b
26
>>> c | d
26
```

**See Also**

- An example of overloading the
`__ior__()`

method to iterate iterables in a`MutableSet`

abstract base class - R. Hettingers OrderedSet recipe (see lines 3 and 10 respectively)
- A thread on Python-ideas on why to use
`|=`

to update a set - A section B.8 of Dive in Python 3 on special methods of Python operators
- In-place binary operators fallback to regular methods, see cpython source code (eval.c and abstract.c). Thanks @asotille.

^{+}_{The in-place bitwise OR operator cannot be applied to literals; assign objects to names.}

^{++}_{Special methods return the same operations as their corresponding operators.}

In Python, and many other programming languages, `|`

is the bitwise-OR operation. `|=`

is to `|`

as `+=`

is to `+`

, i.e. a combination of operation and asignment.

So `var |= value`

is short for `var = var | value`

.

A common use case is to merge two sets:

```
>>> a = {1,2}; a |= {3,4}; print(a)
{1, 2, 3, 4}
```

#### What does |= (ior) do in Python?

When used with sets it performs union operation.