Search code examples
pythonlistdictionaryif-statementline

Why am I getting different values if I change my 'elif' statement to 'if'?


I have a code where I am trying to compare hydrophilic and hydrophobic interactions. My categories are 'Hydrophilic', 'Hydrophobic' and 'Other'. Every time I try to find out how many of each interaction category there is, I always get always get "Other:0" regardless of how many there should actually be. I know that every file I've tested has plenty of interactions that should be in 'Other'.

I've used an almost identical code successfully for a different project and can't work out what's different now. I have also made sure all the line spacing and indentation is perfect and it still has this problem :(

I tried:

Hydrophilic = 0
Hydrophobic = 0
Other = 0

with open(filename) as f:
   lines = f.readlines()
      for line in lines:
         values = line.split(",")
      
         if values[1] == "HYDROPHOBIC":
            Hydrophobic += 1
         elif values[1] == "HBOND" or "WEAK_HBOND" or "POLAR" or "WEAK_POLAR":
            Hydrophilic += 1
         else:
            Other += 1

sizes = {'Hydrophilic':Hydrophilic, 'Hydrophobic':Hydrophobic, 'Other':Other}

print(sizes)

and was hoping for it to print something along the lines of (Hydrophilic:7, Hydrophobic:4, Other:13) but always get Other:0.

I tried replacing 'elif' for 'if' and got different numbers for hydrophobic and hydrophilic (still 0 for other). I tried swapping the order so that the hydrophilic values are added first and ended up with 0 hydrophobic and 0 other.


Solution

  • Why it happens?

    elif values[1] == "HBOND" or "WEAK_HBOND" or "POLAR" or "WEAK_POLAR":

    When you put or, it assumes that it's a completely different condition. So, it checks if values[1] is "HBOND". If it fails, it goes to the next condition, which is just "WEAK_HBOND". Since there's no equation sign, Python tries to turn the string into a boolean.

    String turns into False if it's empty and into True if it's not empty. Since "HBOND" is not an empty string, it turns into True and the elif block (or the if block if you changed it) gets executed, and the else block does not work.

    Why the value changes when swapping elif to if?

    When you use if both times

    This condition gets executed: (assuming it's true): if values[1] == "HYDROPHOBIC": Python goes to the next condition: if values[1] == "HBOND" or "WEAK_HBOND" or "POLAR" or "WEAK_POLAR": It sees if, so it checks the condition. If values[1] == "HBOND" is true, it executes. If it's not true, then it goes to the next one. "WEAK_HBOND" It sees a string. Since there's no equation (==), it turns the string into boolean and executes the condition. So, on one iteration, it added 1 to both Hydrophobic and Hydrophilic variables.

    When you use elif

    This condition gets executed: (assuming it's true): if values[1] == "HYDROPHOBIC": Python goes to the next line: elif values[1] == "HBOND" or "WEAK_HBOND" or "POLAR" or "WEAK_POLAR": It sees elif, so it checks the previous condition associated with the elif block. It was the previous if which was true, so it will skip it anyways. It won't increase the Hydrophilic value if the if condition before (values[1] == "HYDROPHOBIC") was true.

    What about the else part?

    else never gets executed in the both cases anyways. When you are using elif, it just either executes the elif or the previous if block, skipping the else block. If you use if in both cases, as I explained before, Python turns the "HBOND" string into a boolean, and assumes that the if block (second one) is true, not executing the else block.

    How to fix it?

    There are multiple options:

    1. Group your strings into an array and use the in operator: elif values[1] in ["HBOND", "WEAK_HBOND", "POLAR", "WEAK_POLAR"]:
    2. Write the == sign for every single string out there: elif values[1] == "HBOND" or values[1] == "WEAK_HBOND" or values[1] == "POLAR" or values[1] == "WEAK_POLAR": Notice how I typed out values[1] == after or every single time, so that Python knows I'm comparing values[1] and instead of turning it into a boolean it does the equation (==)

    In both cases, use elif instead of if for the second condition (elif values[1] == ...)