0

What's happening in Python to make the following different?

>>> one = 1
>>> one is not False
True
>>> one is (not False)
False

Thinking of not as simply negating what comes after it, I would've thought they'd both have the same output as the second. What's happening to make them different? What are the "order of operations" of the first example?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Grant Pitt
  • 471
  • 5
  • 10
  • Try `1 is True` and see what you get. – Barmar May 20 '22 at 15:44
  • Does this answer your question? [not (not false) = True?](https://stackoverflow.com/questions/30803777/not-not-false-true) – ahmed May 20 '22 at 15:44
  • 3
    These aren't the same comparisons... `one is (not False)` is the same as `one is True`. If you want to negate `one is True`, you'd write `not (one is True)`, which is the same as `one is not True` – OneCricketeer May 20 '22 at 15:48
  • 1
    @ahmed That's not really the same thing. That question is about multiple negations; this one hinges on `is not x` working differently than `is (not x)`. – CrazyChucky May 20 '22 at 15:51
  • I assume there has to be a dupe of this, but I can't find it yet. This is close/related: https://stackoverflow.com/questions/4485180/python-is-not-operator – CrazyChucky May 20 '22 at 15:56

2 Answers2

3

The first instance asks if one is not False which it is because "one" is 1 so the result is True. Here, the is not acts as its own operator.

The second instance asks if one is (not False) which is the same as asking if one is True, but one is not True it is 1. Here, the not is modifying the False to make it True

Keep in mind that is is not the same as ==.

For example 1 == True is True, but 1 is True is False.

Telan
  • 281
  • 1
  • 5
  • 1
    "not is modifying the is " No, `is not` is *it's own operator* – juanpa.arrivillaga May 20 '22 at 15:55
  • @juanpa.arrivillaga I guess one could argue that at some ("parser"?) level, the `not` does modify the `is`. For example [this grammar excerpt](https://docs.python.org/3/reference/expressions.html#comparisons) says `"is" ["not"]`, making it look like an `is` with an optional `not` modifier. And I wouldn't be surprised if the parsing were implemented like that, i.e., first recognizing the `is` and then "switching" to `is not` when it sees the `not`. – Kelly Bundy May 20 '22 at 16:23
  • That might be misleading. The [full grammar](https://docs.python.org/3/reference/grammar.html), for instance, has `isnot_bitwise_or` and `is_bitwise_or` as two separate non-terminals, one consisting of the tokens `'is'` and `'not`, the other having only `'is'`, without implying any kind of modifier relationship between the two. `is not` could just as well have been spelled `aint` as far as the parser is concerned. – chepner May 20 '22 at 17:16
3

You can use the ast module to see how Python parses the two differently.

In the first case, the parser recognizes is not as a single (two-word) operator, with operands one and False.

>>> print(ast.dump(ast.parse("one is not False"), indent=4))
Module(
    body=[
        Expr(
            value=Compare(
                left=Name(id='one', ctx=Load()),
                ops=[
                    IsNot()],
                comparators=[
                    Constant(value=False)]))],
    type_ignores=[])

In the second case, the parser recognizes is as a single (one-word) operator, with operands one and not False.

>>> print(ast.dump(ast.parse("one is (not False)"), indent=4))
Module(
    body=[
        Expr(
            value=Compare(
                left=Name(id='one', ctx=Load()),
                ops=[
                    Is()],
                comparators=[
                    UnaryOp(
                        op=Not(),
                        operand=Constant(value=False))]))],
    type_ignores=[])
chepner
  • 497,756
  • 71
  • 530
  • 681