What does |= (ior) do in Python?
Question:
Google won’t let me search |=
so I’m having trouble finding relevant documentation. Anybody know?
Answers:
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}
It performs a binary bitwise OR of the left-hand and right-hand sides of the assignment, then stores the result in the left-hand variable.
http://docs.python.org/reference/expressions.html#binary-bitwise-operations
This is just an OR operation between the current variable and the other one. Being T=True
and F=False
, see the output graphically:
r
s
r|=s
T
T
T
T
F
T
F
T
T
F
F
F
For example:
>>> r=True
>>> r|=False
>>> r
True
>>> r=False
>>> r|=False
>>> r
False
>>> r|=True
>>> r
True
When used with sets it performs union operation.
|=
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 sets assigned to 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 dicts assigned to 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 counters assigned to 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 numbers assigned to 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
Let’s 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. Hettinger’s 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 @asottile.
- A post on how python handles displaying prepended zeros in bitwise computations
+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.
It’s bitwise or.
Let’s say we have 32 | 10
, picture 32 and 10 in binary:
32 = 10 0000
10 = 00 1010
Now because |
is the OR operation, do a bitwise-or on the two numbers
i.e 1 or 0 –> 1, 0 or 0 –> 0. Continue this down the chain:
10 0000 | 00 1010 = 10 1010.
Now change the binary into a decimal, 10 1010 = 42
.
For |=
, think of the known examples, x +=5
. It means x = x + 5,
therefore if we have x |= 5
, it means x = x bitwiseor with 5
.
In Python,|=(ior) works like union operation.
like if x=5 and x|=5 then both the value will first convert in binary value then the union operation will perform and we get the answer 5.
To give a use-case (after spending time with the other answers):
def process(item):
return bool(item) # imagine some sort of complex processing taking place above
def any_success(data): # return True if at least one is successful
at_least_one = False
for item in data:
at_least_one |= process(item)
return at_least_one
>>> any_success([False, False, False])
False
>>> any_success([True, False, False])
True
>>> any_success([False, True, False])
True
Basically any
without the short-circuiting: might be useful if you need to process every item and record at least one success etc.
See also the caveats in this answer
Hopefully this also helps others to understand:
dict1 = {'a': 'dict1', 'b': 'dict1', 'c': 'dict1'}
dict2 = {'c': 'dict2', 'd': 'dict2', 'e': 'dict2'}
dict3 = dict1.copy()
dict3 = dict3 | dict2
dict4 = dict1.copy()
dict4 |= dict2
print(f'dict1:n {dict1}')
print(f'dict2:n {dict2}')
print(f'dict1 after dict1 = dict1 | dict2 (dict2 index c replaces dict1 index c, items in dict1 are discarded if present in dict2):n {dict3}')
print(f'dict1 after dict1 |= dict2 (same behaviour as dict1 = dict1 | dict2):n {dict4}')
dict5 = dict1.copy()
dict5 = dict2 | dict5
dict6 = dict2.copy()
dict6 |= dict1
print(f'dict1 after dict1 = dict2 | dict1 (dict2 index c is missing, dict1 index c was retained, items in dict2 are discarded if present in dict1):n {dict5}')
print(f'dict2 after dict2 |= dict1 (same behaviour as dict2 = dict2 | dict1):n {dict6}')
dict1:
{'a': 'dict1', 'b': 'dict1', 'c': 'dict1'}
dict2:
{'c': 'dict2', 'd': 'dict2', 'e': 'dict2'}
dict1 after dict1 = dict1 | dict2 (dict2 index c replaces dict1 index c, items in dict1 are discarded if present in dict2):
{'a': 'dict1', 'b': 'dict1', 'c': 'dict2', 'd': 'dict2', 'e': 'dict2'}
dict1 after dict1 |= dict2 (same behaviour as dict1 = dict1 | dict2):
{'a': 'dict1', 'b': 'dict1', 'c': 'dict2', 'd': 'dict2', 'e': 'dict2'}
dict1 after dict1 = dict2 | dict1 (dict2 index c is missing, dict1 index c was retained, items in dict2 are discarded if present in dict1):
{'c': 'dict1', 'd': 'dict2', 'e': 'dict2', 'a': 'dict1', 'b': 'dict1'}
dict2 after dict2 |= dict1 (same behaviour as dict2 = dict2 | dict1):
{'c': 'dict1', 'd': 'dict2', 'e': 'dict2', 'a': 'dict1', 'b': 'dict1'}
It means bitwise OR operation.
Example :
x = 5
x |= 3 #which is similar to x = x | 3
print(x)
Answer : 7
How does it works?
The binary of 5 is : 0 1 0 1
The binary of 3 is : 0 0 1 1
OR operation : (If one of both sides are 1/True then result is 1/True)
0 1 0 1 #Binary of 5
0 0 1 1 #Binary of 3
---------------------
0 1 1 1 #Binary of 7
So, the answer is 7
|
is bitwise OR. So x |= y
is equivalent* to x = x | y
.
For sets, |
takes on a related meaning: set unions. The same way you would take the intersection of 2 sets in math using OR, you can do it in python using |
*Note: The 2 expressions are not 100% equivalent. After x |= y
, id(x) == id(y)
. After x = x | y
, id(x) != id(y)
Google won’t let me search |=
so I’m having trouble finding relevant documentation. Anybody know?
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}
It performs a binary bitwise OR of the left-hand and right-hand sides of the assignment, then stores the result in the left-hand variable.
http://docs.python.org/reference/expressions.html#binary-bitwise-operations
This is just an OR operation between the current variable and the other one. Being T=True
and F=False
, see the output graphically:
r | s | r|=s |
---|---|---|
T | T | T |
T | F | T |
F | T | T |
F | F | F |
For example:
>>> r=True
>>> r|=False
>>> r
True
>>> r=False
>>> r|=False
>>> r
False
>>> r|=True
>>> r
True
When used with sets it performs union operation.
|=
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 sets assigned to 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 dicts assigned to 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 counters assigned to 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 numbers assigned to 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
Let’s 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 aMutableSet
abstract base class - R. Hettinger’s 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 @asottile.
- A post on how python handles displaying prepended zeros in bitwise computations
+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.
It’s bitwise or.
Let’s say we have 32 | 10
, picture 32 and 10 in binary:
32 = 10 0000
10 = 00 1010
Now because |
is the OR operation, do a bitwise-or on the two numbers
i.e 1 or 0 –> 1, 0 or 0 –> 0. Continue this down the chain:
10 0000 | 00 1010 = 10 1010.
Now change the binary into a decimal, 10 1010 = 42
.
For |=
, think of the known examples, x +=5
. It means x = x + 5,
therefore if we have x |= 5
, it means x = x bitwiseor with 5
.
In Python,|=(ior) works like union operation.
like if x=5 and x|=5 then both the value will first convert in binary value then the union operation will perform and we get the answer 5.
To give a use-case (after spending time with the other answers):
def process(item):
return bool(item) # imagine some sort of complex processing taking place above
def any_success(data): # return True if at least one is successful
at_least_one = False
for item in data:
at_least_one |= process(item)
return at_least_one
>>> any_success([False, False, False])
False
>>> any_success([True, False, False])
True
>>> any_success([False, True, False])
True
Basically any
without the short-circuiting: might be useful if you need to process every item and record at least one success etc.
See also the caveats in this answer
Hopefully this also helps others to understand:
dict1 = {'a': 'dict1', 'b': 'dict1', 'c': 'dict1'}
dict2 = {'c': 'dict2', 'd': 'dict2', 'e': 'dict2'}
dict3 = dict1.copy()
dict3 = dict3 | dict2
dict4 = dict1.copy()
dict4 |= dict2
print(f'dict1:n {dict1}')
print(f'dict2:n {dict2}')
print(f'dict1 after dict1 = dict1 | dict2 (dict2 index c replaces dict1 index c, items in dict1 are discarded if present in dict2):n {dict3}')
print(f'dict1 after dict1 |= dict2 (same behaviour as dict1 = dict1 | dict2):n {dict4}')
dict5 = dict1.copy()
dict5 = dict2 | dict5
dict6 = dict2.copy()
dict6 |= dict1
print(f'dict1 after dict1 = dict2 | dict1 (dict2 index c is missing, dict1 index c was retained, items in dict2 are discarded if present in dict1):n {dict5}')
print(f'dict2 after dict2 |= dict1 (same behaviour as dict2 = dict2 | dict1):n {dict6}')
dict1:
{'a': 'dict1', 'b': 'dict1', 'c': 'dict1'}
dict2:
{'c': 'dict2', 'd': 'dict2', 'e': 'dict2'}
dict1 after dict1 = dict1 | dict2 (dict2 index c replaces dict1 index c, items in dict1 are discarded if present in dict2):
{'a': 'dict1', 'b': 'dict1', 'c': 'dict2', 'd': 'dict2', 'e': 'dict2'}
dict1 after dict1 |= dict2 (same behaviour as dict1 = dict1 | dict2):
{'a': 'dict1', 'b': 'dict1', 'c': 'dict2', 'd': 'dict2', 'e': 'dict2'}
dict1 after dict1 = dict2 | dict1 (dict2 index c is missing, dict1 index c was retained, items in dict2 are discarded if present in dict1):
{'c': 'dict1', 'd': 'dict2', 'e': 'dict2', 'a': 'dict1', 'b': 'dict1'}
dict2 after dict2 |= dict1 (same behaviour as dict2 = dict2 | dict1):
{'c': 'dict1', 'd': 'dict2', 'e': 'dict2', 'a': 'dict1', 'b': 'dict1'}
It means bitwise OR operation.
Example :
x = 5
x |= 3 #which is similar to x = x | 3
print(x)
Answer : 7
How does it works?
The binary of 5 is : 0 1 0 1
The binary of 3 is : 0 0 1 1
OR operation : (If one of both sides are 1/True then result is 1/True)
0 1 0 1 #Binary of 5
0 0 1 1 #Binary of 3
---------------------
0 1 1 1 #Binary of 7
So, the answer is 7
|
is bitwise OR. So x |= y
is equivalent* to x = x | y
.
For sets, |
takes on a related meaning: set unions. The same way you would take the intersection of 2 sets in math using OR, you can do it in python using |
*Note: The 2 expressions are not 100% equivalent. After x |= y
, id(x) == id(y)
. After x = x | y
, id(x) != id(y)