Python Forum

Full Version: Comparison Operator "is" idle vs python command
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
I don't understand why the following results aren't the same. c = (a is b) returns True while (a is b) in python idle returns False. What aren't I understanding?

Pycharm/VS Code

a = "many paths"
b = "many paths"
c = (a is b)
print (c)  # This returns True
PYTHON:
>>> a = "many paths"
>>> b = "many paths"
>>> a is b
False

That is supposed to be a print ( c )
The is operator checks if two variables point to the same object
== checks to see if two variables contain the same data
if 'is' returns True, == must also be True, but the opposite may or mayy not be True.
Here's what I get with various length strings, on my machine, using python 3.7.
>>> a = "blah"
>>> b = "blah"
>>> a is b
True
>>> c = "blah blah blah"
>>> d = "blah blah blah"
>>> c is d
False
is checks whether two objects are the same. That's unrelated to whether or not they're equal to each other. The reason this sometimes gives True for strings, is because small strings will be cached and re-used (sometimes), because they're immutable and can't change. Not all python implementations do this, though, which is why you shouldn't be using is to compare strings. You should only be using it to compare with None, anything else should be using equality checks ==.
Edit: Even the results in REPL are not always reproducibly. Don't use the is operator for str, bytes, int, float.

I guess the AST-Parser and/or Bytecode optimizer scans for equal literals and replaces them with a reference to the same object.
This explains why the first result is True and the second one False.
In interactive mode (repl) a and b referring to two different str objects.

Use only the is operator, if you want to check Identity.
You can check the identity of Singletons like None, True, False, ....
Also of all other objects like list, tuple, dict, set, functions, classes, types.
Surprise, also for str and bytes, but not if you create new literals.
WORK = "work"
RUN = "run"
STOP = "stop"

def some_function(choice):
    if choice is WORK:
        print('Go to work')
    elif choice is RUN:
        print('You are late. Run baby..')
    elif choice is STOP:
        print('Go Home.')
    else:
        print('Got invalid input')

some_function("work") # <- invalid input
some_function(WORK)
"work" is not WORK and "run" is not RUN and "stop" is not STOP
The good thing is, if you enter this in Python 3.8, you get a nice SyntaxWarning and there is some auto correction going on in the background.
Error:
SyntaxWarning: "is not" with a literal. Did you mean "!="?
With mutable objects this should be clear.
d1 = {}
d2 = {}
The name d1 refers to a dict
The name d2 refers to another new dict
Same for tuple- list-literals.

Now a example with immutable objects:
a = 5
b = 5
Name a and name b should refer to two different objects.
But this it not the case. The Python interpreter creates a range of numbers in memory and literals like the 5 is reusing the object for 5 from memory. But this is not the case for bigger numbers. You know, memory is limited.

The differences you see, comes from optimization and implementation details.
If you want to check for equality, don't use the is operator.