Search code examples
pythonif-statementequivalent

Yoda condition with "not x is None"


The previous dev has left a really strange not x is None yoda condition in the code:

>>> x = None
>>> not x is None
False
>>> x = 1
>>> not x is None
True

After some testing, I seem the same output as x is not None.

>>> x = None
>>> not x is None
False
>>> x is not None
False
>>> x = 1
>>> not x is None
True
>>> x is not None
True

Is not x is None always equivalent to x is not None?

To break down the condition, is it not (x is None) or (not x) is None? Or will the former always be equivalent to the latter?


Solution

  • Since is has higher precendence than not, then the expressions are equivalent:

    In case x = None: x is None evaluates to True, and not x is None evaluates to False In case x = 1: x is None evaluates to False, and not x is None evaluates to True

    In case x = None: x is not None evaluates to False In case x = 1: x is not None evaluates to True.

    Therefore, even though the actions are not syntactically equivalent, the results are equivalent.

    This is the AST of not x is None:

    enter image description here

    This is the AST of x is not None:

    enter image description here

    As can be seen in the second diagram, the inner node is the compare node, and therefore x is None is evaluated before the not.

    Regarding actual evaluation of the expression, it seems that python creates the same bytecode for both. It can be seen in this example:

    def foo(x):
        x is not None
    
    
    def bar(x):
        not x is None
    
    import dis
    dis.dis(foo)
    dis.dis(bar)
    

    As both generate:

          0 LOAD_FAST                0 (x)
          3 LOAD_CONST               0 (None)
          6 COMPARE_OP               9 (is not)
          9 POP_TOP             
         10 LOAD_CONST               0 (None)
         13 RETURN_VALUE