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?
Much 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.
I use that in match case operations, but usually when is just two possibilities, try something like this and see if works
match coin:
case 5 | 10 | 20:
…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.
Thank you for the thorough explanation. It makes sense to me why I had the error that I did. I’ll keep this in mind next time when I consider using a bitwise operator.
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.
python in general tends toward readability over performance optimisation… you’re right they’re an advanced concept, and i’d say if you ever use bitwise operators in python they should be wrapped in some descriptive and very minimal function: treat it like a black box, because the next person that comes along likely won’t understand what’s happening without a pretty good description
a bit field is just not a descriptive data structure, so manipulate it directly as little as possible
i’d also say that most peoples use of bitwise operators is when unpacking external data formats (network traffic, operating system primitives, files formats, etc) and they’re usually wrapped in data structures that make those things more pythonic
unless you know you need bitwise operators, you probably don’t need bitwise operators
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.
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 enumsWow that’s neat! Thanks for bringing this up.
The feature flags example should be rewritten to use
enum.Flag
one small gripe i have is that the repr¹ doesn’t handle aliases (ie items with more than one bit set) that well , but tbh its not an easy problem
example to illustrate the problem :
class Foo(enum.Flag): A = auto() B = auto() C = auto() # no D AB = 0b0011 CD = 0b1100 print(Foo.AB | Foo.C) # <Foo.A|B|C: 7> NOT <Foo.AB|C: 7> print(Foo.CD | Foo.A) # <Foo.A|C|CD: 13> NOT <Foo.A|CD: 7>
its a minor thing but it annoys me a bit
[1]: the
_name_
member , which is used by__repr__
, of an enum member is actually generated either when the individual enum class is created or when the value is first needed by_missing_
. also the docs call these names surrounded by single underscores “sunder” names
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.
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.
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.
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.