if coin == 25 | 10 | 5:
If I replace the ‘|’ with ‘or’ the code runs just fine. I’m not sure why I can’t use ‘|’ in the same statement.
Doing the following doesn’t work either:
if coin == 25 | coin == 10 | coin == 5:
I know bitwise operators can only be used with integers, but other then that is there another difference from logical operators?
while many great things have been said in this thread i’ll also link to the docs for
enum.Flag
(docs.python.org) which wraps bitmap integer enumsMuch to unpack here…
coin == 25 | 10 | 5
…will evaluate as True if coin is equal to the bitwise OR of 25, 10 and 5 - i.e. 31. In other word, it’s equivalent to
coin == 31
. That’s because the bitwise OR has precedence over the == operator. See operator precedence in Python.If I replace the ‘|’ with ‘or’ the code runs just fine.
It probably doesn’t. If you replace
|
withor
, you have the statementcoin == 25 or 10 or 5
which is always True in theif
statement because it’s evaluated as(coin == 25) or (not 0) or (not 0)
in anif
statement.coin == 25 | coin == 10 | coin == 5
…will evaluate as
coin == (25 | coin) == (10 | coin) == 5
. Again, operator precedence.What you want to do is this:
if coin in [25, 10, 5]:
or
if coin in (25, 10, 5):
or simply
if coin == 25 or coin == 10 or coin == 5:
Don’t create problems and confusion for the next guy who reads your code for nothing. Simple and readable are your friends 🙂
Thanks. I think I understand why I wouldn’t want to use it in this case. But what is an example of where I can use it? This makes me think I should avoid using bitwise operators with integers and keep it to strings only, but I know that’s not true from what I’ve learned.
When you’re working with the binary representation of numbers.
In your code you had three numbers 25, 10 and 5. If we write those number in binary we get:
- 25: 0b00011001
- 10: 0b00001010
- 5: 0b00000101
(The 0b at the start is just a way of saying “this is binary”)
When you do a bitwise-or, it’s a bit like adding up but you don’t bother with carrying anything. So let’s do 25 | 10, starting at the right-hand end going bit by bit (bitwise):
- 0 | 1 = 1
- 1 | 0 = 1
- 0 | 0 = 0
- 1 | 1 = 1
- 1 | 0 = 1
- 0 | 0 = 0 for all the rest
So the result is 0b00011011 which is 27.
So now you’re asking “when would I ever need to do such a thing?” and the flippant answer is “you’ll know when you need it”.
You’re looking for more though, I know. Basically computers often put multiple bits of data into bitstreams (long sequences of bits). Think networking and file storage. Constructing these bitstreams is done with bitwise operators like |, &, ^, << and >>. Together they form a different type of maths to what you’re used to.
These operators work in a very similar way to how +, -, * and / work. They take two numbers and return a third. If we rewrite your code using operators you’re more familiar with…
if coin == 25 | 10 | 5: # if coin == 31 ... if coin == 25 + 10 + 5: # if coin == 40 ...
…you can see it’s obviously wrong because you’re doing one comparison with the result of the operation (addition or bitwise-or), not three comparisons.
But what is an example of where I can use it?
Aside from operations on bitfields, a bitwise operator can be useful in several “non bits” cases. For instance:
value & 1
evaluates to 1 ifvalue
is odd (and will evaluate to True in anif
statement)
value >> 1
dividesvalue
by 2 (integer division)But usually bitwise operators are for when you want to manipulate bits in values. For instance:
value | 5
returnsvalue
with bits 1 and 3 set to True
value & 0xffff
returns the 16 least-significant bits invalue
(usually you do this to make sure it will fit in 2 bytes in memory for example)
value & (0xffff ^ 5)
returns the lower 16 bits ofvalue
with bits 1 and 3 set to FalseEtc.
Thank you for the reply. It seems bitwise operators are somewhat of an advanced concept that I may revisit down the road.
honestly yes you’re probably not going to use them a lot, if at all, especially in python
You might use them with sets:
a = {1, 2, 3} b = {2, 3, 4} a | b # {1, 2, 3, 4} a & b # {2, 3} a ^ b # {1, 4} a - b # {1} b - a # {4}
They’re quite simple. Just convert the values to binary and apply the applicable truth tables. Just remember operator precedence when you use them, and in doubt, don’t trust your luck and apply parentheses generously 🙂
And write generous unit tests so the next person doesn’t accidentally mess it up.
a use case – feature flags
Mix and match to plan your day
will i be going home today?
>>> OUTRAGED_BY_NEWS = 0b00000001 >>> GET_A_COFFEE = 0b00000010 >>> GO_FOR_A_HIKE = 0b00000100 >>> GO_FOR_A_RUN = 0b00001000 >>> GO_HOME = 0b00010000 >>> various_flags_ored_together = GET_A_COFFEE | GO_FOR_A_RUN | GO_HOME >>> various_flags_ored_together & GO_HOME == GO_HOME True >>> various_flags_ored_together & GO_FOR_A_HIKE == GO_FOR_A_HIKE False >>> various_flags_ored_together = GET_A_COFFEE | GO_FOR_A_RUN | GO_HOME >>> bin(various_flags_ored_together) '0b11010' >>> various_flags_ored_together & OUTRAGED_BY_NEWS == OUTRAGED_BY_NEWS >>> False >>> bin(OUTRAGED_BY_NEWS) >>> '0b1' >>> various_flags_ored_together >> OUTRAGED_BY_NEWS >>> bin(various_flags_ored_together) '0b1101'
Guess haven’t gone for a hike today…maybe tomorrow
right shift removes bit at flag position. Which, in this case, happens to correspond to the right most bit.
use case – file access permissions
For those looking to check file access permissions there is the stat module
>>> import stat >>> from pathlib import Path >>> path_f = Path.home().joinpath(".bashrc") >>> stat.S_IRUSR 256 >>> path_f.stat().st_mode 33188 >>> is_owner_read = path_f.stat().st_mode & stat.S_IRUSR == stat.S_IRUSR >>> is_owner_read True >>> path_f = Path("/etc/fstab") >>> is_other_write = path_f.stat().st_mode & stat.S_IWOTH == stat.S_IWOTH >>> is_other_write False
Assumes
~/.bashrc
exists, if not choose a different file you are owner and have read access to.path_f.stat().st_mode & stat.S_IRUSR == stat.S_IRUSR
Looking thru the mundane file (not Linux access control list) permissions. All those flags are crammed into st_mode. In st_mode, on/off bit at 2^8 is that on?
Sources
read user access stat.S_IRUSR
write others access stat.S_IWOTH
||
is the logical OR in most languages I know of, but I’m pretty sure python only has theor
keyword, no shorthand.Bitwise OR applies the logic to the individual bits in the underlying data. Think about how you would add two large numbers by hand. Write one number above the other and add at each position. Bitwise or is like that, except you OR the two bits in each position instead of adding them.
In your example (you can do an OR with n inputs, the result is 1 if any input is 1):
11001
25
01010
10
00101
5
----- OR
11111
31So your code is actually being interpreted as
if coin == 31:
| is not equivalent to “or”. In bitwise operations the integer is converted into bits and the operation is done on a per-bit level. See: https://www.geeksforgeeks.org/python-bitwise-operators/
Eg.
1 | 2
is 3 where as1 or 3
is 1Exactly. OP is looking for a Boolean logical operator “or” and not the bitwise operator “|”.
I did come across that link but didn’t quite understand it. If looking only at 25 | 10, does the code not run as expected because 25 is 5 digits long and 10 is 4 digits long? Is that what’s meant by “two equivalent length bit designs”?
Also, I can’t tell if 10 | 4 = 7 or 10 | 4 = 14.
0d10 = 0b00001010 0d04 = 0b00000100 1010 | 0100 ------ 1110 0b00001110 = 0d14 0d25 = 0b00011001 0d10 = 0b00001010 11001 | 01010 ------- 11011 0b00011011 = 0d27
If an int is only x bytes long, but y bytes are needed for an action, it’s just padded with 0’s to the left. So 0b110 = 0b0110 = 0b00000110. Usually you will use either 8, 16, 32 or 64 digits/bits (char, short, int and long respectively, and 1, 2, 4 and 8 bytes long, 1 byte = 8 bits. So you’ll usually align it with bytes.) However, for calculating like this removing trailing zeroes can make it more tidy, and sometimes 4 or 2 bits are used too. And bools technically only use 1 bit.
Thank you. Not sure why in the link the arithmetic in green results in 7.
I don’t have the answer, but if you are looking to do something like that you could simply do :
if coin in (25, 10, 5):
Or use a list but I think using a tuple is better as your values are fixed.Yes I did eventually think of that as well but just wanted to understand why ‘|’ wasn’t producing the results I expected.
You want the keyword “or” rather than the bitwise operator. Alternatively, use “if coin in {25, 10, 5}”. The curly braces denote a set, which is implemented as a hash table, so the lookup will be fast even when the number of choices is large.
Consider using a tuple instead for potentially lower runtime cost on initialization and no accidental mutation:
if coin in (25, 10, 5):
If the list is long and used frequently, I’d go with the set.
Part of the problem is operator precedence - it’s ORing together the three numbers, then comparing that to “coin”.
5 = 00101 10= 01010 25= 11001 11111 = 31
It’s testing if coin equals 31.
Thank you for breaking it down.
I’m just now sure when it is appropriate to use ‘|’. If bitwise operators can only be used with integers (and not floats), what’s an example where I can use it.
Have a look at the result of your bitwise operation.