this post was submitted on 09 Mar 2025
18 points (87.5% liked)

Python

6788 readers
93 users here now

Welcome to the Python community on the programming.dev Lemmy instance!

📅 Events

PastNovember 2023

October 2023

July 2023

August 2023

September 2023

🐍 Python project:
💓 Python Community:
✨ Python Ecosystem:
🌌 Fediverse
Communities
Projects
Feeds

founded 2 years ago
MODERATORS
 

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?

top 26 comments
sorted by: hot top controversial new old
[–] [email protected] 46 points 1 day ago* (last edited 1 day ago) (1 children)

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 | with or, you have the statement coin == 25 or 10 or 5 which is always True in the if statement because it's evaluated as (coin == 25) or (not 0) or (not 0) in an if 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 🙂

[–] [email protected] 3 points 1 day ago (3 children)

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.

[–] [email protected] 2 points 7 hours ago

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

[–] [email protected] 8 points 1 day ago* (last edited 1 day ago) (1 children)

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.

[–] [email protected] 3 points 8 hours ago

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.

[–] [email protected] 10 points 1 day ago* (last edited 1 day ago) (1 children)

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 if value is odd (and will evaluate to True in an if statement)
value >> 1 divides value by 2 (integer division)

But usually bitwise operators are for when you want to manipulate bits in values. For instance:

value | 5 returns value with bits 1 and 3 set to True
value & 0xffff returns the 16 least-significant bits in value (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 of value with bits 1 and 3 set to False

Etc.

[–] [email protected] 5 points 1 day ago (3 children)

Thank you for the reply. It seems bitwise operators are somewhat of an advanced concept that I may revisit down the road.

[–] [email protected] 1 points 13 minutes ago* (last edited 10 minutes ago)

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

[–] [email protected] 9 points 1 day ago (1 children)

honestly yes you're probably not going to use them a lot, if at all, especially in python

[–] [email protected] 3 points 20 hours ago

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}
[–] [email protected] 2 points 1 day ago (1 children)

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 🙂

[–] [email protected] 1 points 20 hours ago

And write generous unit tests so the next person doesn't accidentally mess it up.

[–] yardy_sardley 7 points 1 day ago

|| is the logical OR in most languages I know of, but I'm pretty sure python only has the or 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 31

So your code is actually being interpreted as if coin == 31:

[–] [email protected] 8 points 1 day ago (2 children)

| 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 as 1 or 3 is 1

[–] [email protected] 5 points 1 day ago

Exactly. OP is looking for a Boolean logical operator “or” and not the bitwise operator “|”.

[–] [email protected] 1 points 1 day ago (1 children)

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.

[–] [email protected] 5 points 1 day ago* (last edited 1 day ago) (1 children)
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.

[–] [email protected] 2 points 1 day ago

Thank you. Not sure why in the link the arithmetic in green results in 7.

[–] [email protected] 6 points 1 day ago (1 children)

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.

[–] [email protected] 2 points 20 hours ago* (last edited 20 hours ago)

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.

[–] [email protected] 2 points 21 hours ago* (last edited 20 hours ago)

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

os.stat_result

pathlib.Path.stat

[–] [email protected] 6 points 1 day ago* (last edited 1 day ago) (1 children)

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.

[–] [email protected] 1 points 1 day ago

Yes I did eventually think of that as well but just wanted to understand why '|' wasn't producing the results I expected.

[–] [email protected] 4 points 1 day ago (1 children)

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.

[–] [email protected] 2 points 1 day ago* (last edited 1 day ago)

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.

[–] [email protected] 1 points 1 day ago

Have a look at the result of your bitwise operation.