Skip Navigation

Why can't I use the '|' bitwise operator in this statement?

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?

32 comments
  • 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 🙂

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

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

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

  • 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

32 comments