Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Different results when using PyCharm and IDLE/python

I was just reading about the 'unexpected result of is operator' which happens because Python cache numbers between -5 and 256.

This was discussed here: "is" operator behaves unexpectedly with integers

and here: "is" and "id" in Python 3.5

When I run one of the examples given there, I get different results between Python Idle and Python IDE (I'm using Jetbrains Pycharm professional edition - 5.0.4).

When using Python IDLE this is the result:

a = 1000
b = 1000
print (a is b) # prints False

when using Pycharm 5.0.4 this is the result:

a = 1000
b = 1000
print (a is b) # prints True

how could this be? I've rechecked, and my project's Python-Interpreter is exactly the same in both cases (both are Python 3.5.1). Not sure if this is something I've done wrong, and I was hoping if someone could explain this.

Edit:

I know 'a' is 'b' == true iff id(a) == id(b), and that you can check it like some of you mentioned in the comments. Perhaps I should have been more clear, what I don't understand is how could it be that an IDE has different behavior? I thought (and please, correct me, as it seems I'm wrong) that an IDE is just a user-friendly environment that uses external compilers / interpreters, and this is why these are independent of those IDE's (for instance, pycharm supports not only Python, and I could run Eclipse with C compiler, or Java etc. (all of which are not parts of the IDE).

Thanks, Alon.

like image 918
Alonbs Avatar asked May 03 '16 09:05

Alonbs


2 Answers

This is because of how LOAD_CONST byte code works:

Pushes co_consts[consti] onto the stack.

Since integers are stored as constants then assignments to the same integer in the same context will yield the exact same result, we can see that the arguement to LOAD_CONST is 0 for both a and b:

>>> import dis
>>> dis.dis("a = 1000 ; b = 1000")     
  1           0 LOAD_CONST               0 (1000)
              3 STORE_NAME               0 (a)
              6 LOAD_CONST               0 (1000)
              9 STORE_NAME               1 (b)
             12 LOAD_CONST               1 (None)
             15 RETURN_VALUE
                                       # ^ this is the argument 

where as in an interactive session each command is compiled separately (so that they can be executed separately) so the constants will be different:

>>> code1 = compile("a = 1000","<dummy file>","exec")
>>> code2 = compile("a = 1000","<dummy file>","exec")
>>> code1.co_consts, code2.co_consts
((1000, None), (1000, None))
>>> code1.co_consts[0] is code2.co_consts[0]
False

Similarly the constant in a function will always be the same but it will be different to the constant in other functions:

def f():
    return 1000
def g():
    return 1000 #different code object!!

#these all work
assert f() is f()
assert g() is g()
assert f() is not g()
assert f() is not 1000 and g() is not 1000

Also note that as @AniMenon has pointed out the numbers from -5 to 256 are singletons for optimization so the same will not hold true for numbers in that range.

like image 91
Tadhg McDonald-Jensen Avatar answered Nov 17 '22 17:11

Tadhg McDonald-Jensen


From the documentation for the is operator:

The operators is and is not test for object identity: x is y is true if and only if x and y are the same object.

Now lets check IDLE:

>>> a = 1000
>>> b = 1000
>>> print ( a is b )
False
>>> 
>>> 
>>> id(a)
35334812
>>> id(b)
35334800

PyCharm:

>>> a = 1000
b = 1000
print (a is b)
True
>>> id(a)
36079236
>>> id(b)
36079236

In PyCharm both a and b are the same objects when in IDLE they are not.

Now what's instersting in PyCharm, that if you entering your code line by line, like in IDLE, you'll get the same results as in IDLE:

>>> a = 1000
>>> b = 1000
>>> print (a is b)
False

My guess, that

>>> a = 1000
    b = 1000

is optimized to:

>>> a = b = 1000
>>> print (a is b)
True

So that's why you got same object for a and b

like image 44
Samuel Avatar answered Nov 17 '22 15:11

Samuel