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.
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 use the same symbols, but they’re not bitwise operators anymore.
True, but it has the same semantics.
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.
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
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:
…Edit: just tested and it’s works.
||
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:
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.
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
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
Have a look at the result of your bitwise operation.