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?

  • logging_strict
    link
    fedilink
    arrow-up
    2
    ·
    edit-2
    5 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

  • ExtremeDullard@lemmy.sdf.org
    link
    fedilink
    arrow-up
    40
    ·
    edit-2
    11 hours ago

    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 🙂

    • milon@lemm.eeOP
      link
      fedilink
      arrow-up
      3
      ·
      11 hours ago

      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.

      • wewbull@feddit.uk
        link
        fedilink
        English
        arrow-up
        8
        ·
        edit-2
        9 hours ago

        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.

      • ExtremeDullard@lemmy.sdf.org
        link
        fedilink
        arrow-up
        9
        ·
        edit-2
        11 hours ago

        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.

        • milon@lemm.eeOP
          link
          fedilink
          arrow-up
          5
          ·
          11 hours ago

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

          • ExtremeDullard@lemmy.sdf.org
            link
            fedilink
            arrow-up
            1
            ·
            11 hours ago

            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 🙂

  • Yardy Sardley@lemmy.ca
    link
    fedilink
    arrow-up
    6
    ·
    11 hours 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:

  • solrize@lemmy.world
    link
    fedilink
    arrow-up
    5
    ·
    11 hours ago

    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.

    • sugar_in_your_tea@sh.itjust.works
      link
      fedilink
      arrow-up
      1
      ·
      edit-2
      5 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.

    • milon@lemm.eeOP
      link
      fedilink
      arrow-up
      1
      ·
      12 hours ago

      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.

      • Lucy :3@feddit.org
        link
        fedilink
        arrow-up
        5
        ·
        edit-2
        11 hours ago
        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.

        • milon@lemm.eeOP
          link
          fedilink
          arrow-up
          2
          ·
          11 hours ago

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

  • Matth78@lemm.ee
    link
    fedilink
    English
    arrow-up
    6
    ·
    edit-2
    12 hours ago

    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.

    • milon@lemm.eeOP
      link
      fedilink
      arrow-up
      1
      ·
      12 hours ago

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

  • Eggscellent@sh.itjust.works
    link
    fedilink
    English
    arrow-up
    4
    ·
    12 hours ago

    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.

    • milon@lemm.eeOP
      link
      fedilink
      arrow-up
      2
      ·
      edit-2
      12 hours 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.