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.
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.
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.
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.
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.
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