Search code examples
javapythonc++if-statementmicro-optimization

Is the python "elif" compiled differently from else: if?


I know in languages such as C, C++, Java and C#, (C# example)the else if statement is syntactic sugar, in that it's really just a one else statement followed by an if statement.

else if (conition(s)) { ...

is equal to

else {
    if (condition(s)) { ...
}

However, in python, there is a special elif statement. I've been wondering if this is just shorthand for developers or if there is some hidden optimization python can do because of this, such as be interpreted faster? But this wouldn't make sense to me, as other languages would be doing it too then (such as JavaScript). So, my question is, in python is the elif statement just shorthand for the developers to use or is there something hidden that it gains through doing so?


Solution

  • When you really want to know what is going on behind the scenes in the interpreter, you can use the dis module. In this case:

    >>> def f1():
    ...   if a:
    ...     b = 1
    ...   elif aa:
    ...     b = 2
    ... 
    >>> def f2():
    ...   if a:
    ...     b = 1
    ...   else:
    ...     if aa:
    ...       b = 2
    ... 
    >>> dis.dis(f1)
      2           0 LOAD_GLOBAL              0 (a)
                  3 POP_JUMP_IF_FALSE       15
    
      3           6 LOAD_CONST               1 (1)
                  9 STORE_FAST               0 (b)
                 12 JUMP_FORWARD            15 (to 30)
    
      4     >>   15 LOAD_GLOBAL              1 (aa)
                 18 POP_JUMP_IF_FALSE       30
    
      5          21 LOAD_CONST               2 (2)
                 24 STORE_FAST               0 (b)
                 27 JUMP_FORWARD             0 (to 30)
            >>   30 LOAD_CONST               0 (None)
                 33 RETURN_VALUE        
    >>> dis.dis(f2)
      2           0 LOAD_GLOBAL              0 (a)
                  3 POP_JUMP_IF_FALSE       15
    
      3           6 LOAD_CONST               1 (1)
                  9 STORE_FAST               0 (b)
                 12 JUMP_FORWARD            15 (to 30)
    
      5     >>   15 LOAD_GLOBAL              1 (aa)
                 18 POP_JUMP_IF_FALSE       30
    
      6          21 LOAD_CONST               2 (2)
                 24 STORE_FAST               0 (b)
                 27 JUMP_FORWARD             0 (to 30)
            >>   30 LOAD_CONST               0 (None)
                 33 RETURN_VALUE        
    

    It looks like our two functions are using the same bytecode -- So apparently they're equivalent.

    Careful though, bytecode is an implementation detail of CPython -- There's no telling that all python implementations do the same thing behind the scenes -- All that matters is that they have the same behavior. Working through the logic, you can convince yourself that f1 and f2 should do the same thing regardless of whether the underlying implementation treats it as "syntatic sugar" or if there is something more sophisticated going on.