Why does the `is` operator behave differently in a script vs the REPL?Python 3.6.5 “is” and “==” for integers beyond caching intervalDifferent evaluation for object equality when running Python with file or in a shellUnderstanding Python's “is” operatorConfused about `is` operator with stringsPython 3 integer addresses“is” operator behaves unexpectedly with integersHow do I return multiple values from a function?Does Python have a ternary conditional operator?How do you get the logical xor of two variables in Python?Why does comparing strings using either '==' or 'is' sometimes produce a different result?Running shell command and capturing the outputCreating a singleton in PythonWhy does Python code run faster in a function?Why is “1000000000000000 in range(1000000000000001)” so fast in Python 3?Why is [] faster than list()?

Integer Lists of Noah

LED glows slightly during soldering

Is that a case of "DOUBLE-NEGATIVES" as claimed by Grammarly?

Is it OK to leave real names & info visible in business card portfolio?

Distinguish the explanations of Galadriel's test in LotR

The origin of a particular self-reference paradox

Can I play a mimic PC?

Postgres trigram match acting strange for specific characters

How can I effectively communicate to recruiters that a phone call is not possible?

Can i use larger/smaller circular saw blades on my circular / plunge / table / miter saw?

Through: how to use it with subtraction of functions?

What is the correct parsing of お高くとまる?

How do we handle pauses in a dialogue?

Why is a mixture of two normally distributed variables only bimodal if their means differ by at least two times the common standard deviation?

Why weren't bootable game disks ever a thing on the IBM PC?

Is there a nice way to implement a conditional type with default fail case?

Chorophyll and photosynthesis in plants with coloured leaves

Misrepresented my work history

When I press the space bar it deletes the letters in front of it

What happens when adult Billy Batson says "Shazam"?

Why does the Antonov AN-225 not have any winglets?

Graduate student with abysmal English writing skills, how to help

What is the parallel of Day of the Dead with Stranger things?

What is a "Lear Processor" and how did it work?



Why does the `is` operator behave differently in a script vs the REPL?


Python 3.6.5 “is” and “==” for integers beyond caching intervalDifferent evaluation for object equality when running Python with file or in a shellUnderstanding Python's “is” operatorConfused about `is` operator with stringsPython 3 integer addresses“is” operator behaves unexpectedly with integersHow do I return multiple values from a function?Does Python have a ternary conditional operator?How do you get the logical xor of two variables in Python?Why does comparing strings using either '==' or 'is' sometimes produce a different result?Running shell command and capturing the outputCreating a singleton in PythonWhy does Python code run faster in a function?Why is “1000000000000000 in range(1000000000000001)” so fast in Python 3?Why is [] faster than list()?






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








4















In python, two codes have different results:



a = 300
b = 300
print (a==b)
print (a is b) ## print True
print ("id(a) = %d, id(b) = %d"%(id(a), id(b))) ## They have same address


But in shell mode(interactive mode):



>>> a = 300
>>> b = 300
>>> a is b
False
>>> id(a)
4501364368
>>> id(b)
4501362224


"is" operator has different results.










share|improve this question



















  • 1





    @Aran-Fey: it's not all that important what type of object is being compared this way, but in this particular case it's because the entity that compiled the .py source file noticed that 300 == 300 so made only one 300 instance, while the interpreter that read the >>> lines didn't notice that 300 == 300 so made two separate 300 instances.

    – torek
    Mar 25 at 23:05






  • 3





    Still, is is for object identity. Only use it when that's what you want.

    – Chris
    Mar 25 at 23:05






  • 3





    @Chris I don't think that really answers the question, either. Like torek said, this question is about the difference between running the same code in the REPL vs as a script.

    – Aran-Fey
    Mar 25 at 23:06






  • 5





    As @Chris says. In other words identity of two immutable objects with the same value is incidental and not guaranteed / required. Why it once matches and once doesn't is hence immaterial.

    – Ondrej K.
    Mar 25 at 23:14







  • 1





    Folks, none of those answers actually answers the question. :-(

    – John Szakmeister
    Mar 25 at 23:34

















4















In python, two codes have different results:



a = 300
b = 300
print (a==b)
print (a is b) ## print True
print ("id(a) = %d, id(b) = %d"%(id(a), id(b))) ## They have same address


But in shell mode(interactive mode):



>>> a = 300
>>> b = 300
>>> a is b
False
>>> id(a)
4501364368
>>> id(b)
4501362224


"is" operator has different results.










share|improve this question



















  • 1





    @Aran-Fey: it's not all that important what type of object is being compared this way, but in this particular case it's because the entity that compiled the .py source file noticed that 300 == 300 so made only one 300 instance, while the interpreter that read the >>> lines didn't notice that 300 == 300 so made two separate 300 instances.

    – torek
    Mar 25 at 23:05






  • 3





    Still, is is for object identity. Only use it when that's what you want.

    – Chris
    Mar 25 at 23:05






  • 3





    @Chris I don't think that really answers the question, either. Like torek said, this question is about the difference between running the same code in the REPL vs as a script.

    – Aran-Fey
    Mar 25 at 23:06






  • 5





    As @Chris says. In other words identity of two immutable objects with the same value is incidental and not guaranteed / required. Why it once matches and once doesn't is hence immaterial.

    – Ondrej K.
    Mar 25 at 23:14







  • 1





    Folks, none of those answers actually answers the question. :-(

    – John Szakmeister
    Mar 25 at 23:34













4












4








4


1






In python, two codes have different results:



a = 300
b = 300
print (a==b)
print (a is b) ## print True
print ("id(a) = %d, id(b) = %d"%(id(a), id(b))) ## They have same address


But in shell mode(interactive mode):



>>> a = 300
>>> b = 300
>>> a is b
False
>>> id(a)
4501364368
>>> id(b)
4501362224


"is" operator has different results.










share|improve this question
















In python, two codes have different results:



a = 300
b = 300
print (a==b)
print (a is b) ## print True
print ("id(a) = %d, id(b) = %d"%(id(a), id(b))) ## They have same address


But in shell mode(interactive mode):



>>> a = 300
>>> b = 300
>>> a is b
False
>>> id(a)
4501364368
>>> id(b)
4501362224


"is" operator has different results.







python cpython






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 25 at 23:38









wim

176k58 gold badges345 silver badges475 bronze badges




176k58 gold badges345 silver badges475 bronze badges










asked Mar 25 at 23:00









Bokyun NaBokyun Na

211 bronze badge




211 bronze badge







  • 1





    @Aran-Fey: it's not all that important what type of object is being compared this way, but in this particular case it's because the entity that compiled the .py source file noticed that 300 == 300 so made only one 300 instance, while the interpreter that read the >>> lines didn't notice that 300 == 300 so made two separate 300 instances.

    – torek
    Mar 25 at 23:05






  • 3





    Still, is is for object identity. Only use it when that's what you want.

    – Chris
    Mar 25 at 23:05






  • 3





    @Chris I don't think that really answers the question, either. Like torek said, this question is about the difference between running the same code in the REPL vs as a script.

    – Aran-Fey
    Mar 25 at 23:06






  • 5





    As @Chris says. In other words identity of two immutable objects with the same value is incidental and not guaranteed / required. Why it once matches and once doesn't is hence immaterial.

    – Ondrej K.
    Mar 25 at 23:14







  • 1





    Folks, none of those answers actually answers the question. :-(

    – John Szakmeister
    Mar 25 at 23:34












  • 1





    @Aran-Fey: it's not all that important what type of object is being compared this way, but in this particular case it's because the entity that compiled the .py source file noticed that 300 == 300 so made only one 300 instance, while the interpreter that read the >>> lines didn't notice that 300 == 300 so made two separate 300 instances.

    – torek
    Mar 25 at 23:05






  • 3





    Still, is is for object identity. Only use it when that's what you want.

    – Chris
    Mar 25 at 23:05






  • 3





    @Chris I don't think that really answers the question, either. Like torek said, this question is about the difference between running the same code in the REPL vs as a script.

    – Aran-Fey
    Mar 25 at 23:06






  • 5





    As @Chris says. In other words identity of two immutable objects with the same value is incidental and not guaranteed / required. Why it once matches and once doesn't is hence immaterial.

    – Ondrej K.
    Mar 25 at 23:14







  • 1





    Folks, none of those answers actually answers the question. :-(

    – John Szakmeister
    Mar 25 at 23:34







1




1





@Aran-Fey: it's not all that important what type of object is being compared this way, but in this particular case it's because the entity that compiled the .py source file noticed that 300 == 300 so made only one 300 instance, while the interpreter that read the >>> lines didn't notice that 300 == 300 so made two separate 300 instances.

– torek
Mar 25 at 23:05





@Aran-Fey: it's not all that important what type of object is being compared this way, but in this particular case it's because the entity that compiled the .py source file noticed that 300 == 300 so made only one 300 instance, while the interpreter that read the >>> lines didn't notice that 300 == 300 so made two separate 300 instances.

– torek
Mar 25 at 23:05




3




3





Still, is is for object identity. Only use it when that's what you want.

– Chris
Mar 25 at 23:05





Still, is is for object identity. Only use it when that's what you want.

– Chris
Mar 25 at 23:05




3




3





@Chris I don't think that really answers the question, either. Like torek said, this question is about the difference between running the same code in the REPL vs as a script.

– Aran-Fey
Mar 25 at 23:06





@Chris I don't think that really answers the question, either. Like torek said, this question is about the difference between running the same code in the REPL vs as a script.

– Aran-Fey
Mar 25 at 23:06




5




5





As @Chris says. In other words identity of two immutable objects with the same value is incidental and not guaranteed / required. Why it once matches and once doesn't is hence immaterial.

– Ondrej K.
Mar 25 at 23:14






As @Chris says. In other words identity of two immutable objects with the same value is incidental and not guaranteed / required. Why it once matches and once doesn't is hence immaterial.

– Ondrej K.
Mar 25 at 23:14





1




1





Folks, none of those answers actually answers the question. :-(

– John Szakmeister
Mar 25 at 23:34





Folks, none of those answers actually answers the question. :-(

– John Szakmeister
Mar 25 at 23:34












2 Answers
2






active

oldest

votes


















6














When you run code in a .py script, the entire file is compiled into a code object before executing it. In this case, CPython is able to make certain optimizations - like reusing the same instance for the integer 300.



You could also reproduce that in the REPL, by executing code in a context more closely resembling the execution of a script:



>>> source = """ 
... a = 300
... b = 300
... print (a==b)
... print (a is b)## print True
... print ("id(a) = %d, id(b) = %d"%(id(a), id(b))) ## They have same address
... """
>>> code_obj = compile(source, filename="myscript.py", mode="exec")
>>> exec(code_obj)
True
True
id(a) = 140736953597776, id(b) = 140736953597776


Some of these optimizations are pretty aggressive. You could modify the script line b = 300 changing it to b = 150 + 150, and CPython would still "fold" b into the same constant. If you're interested in such implementation details, look in peephole.c and Ctrl+F for the "consts table".



In contrast, when you run code line-by-line directly in the REPL it executes in a different context. Each line is compiled in "single" mode and this optimization is not available.



>>> scope = 
>>> lines = source.splitlines()
>>> for line in lines:
... code_obj = compile(line, filename="<I'm in the REPL, yo!>", mode="single")
... exec(code_obj, scope)
...
True
False
id(a) = 140737087176016, id(b) = 140737087176080
>>> scope['a'], scope['b']
(300, 300)
>>> id(scope['a']), id(scope['b'])
(140737087176016, 140737087176080)





share|improve this answer

























  • There is no optimization for b=150+150 in Python3.6, but with later versions.

    – ead
    Mar 26 at 20:56


















4














There are actually two things to know about CPython and its behavior here.
First, small integers in the range of [-5, 256] are interned internally.
So any value falling in that range will share the same id, even at the REPL:



>>> a = 100
>>> b = 100
>>> a is b
True


Since 300 > 256, it's not being interned:



>>> a = 300
>>> b = 300
>>> a is b
False


Second, is that in a script, literals are put into a constant section of the
compiled code. Python is smart enough to realize that since both a and b
refer to the literal 300 and that 300 is an immutable object, it can just
go ahead and reference the same constant location. If you tweak your script
a bit and write it as:



def foo():
a = 300
b = 300
print(a==b)
print(a is b)
print("id(a) = %d, id(b) = %d" % (id(a), id(b)))


import dis
dis.disassemble(foo.__code__)


The beginning part of the output looks like this:



2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)

...


As you can see, CPython is loading the a and b using the same constant slot.
This means that a and b are now referring to the same object (because they
reference the same slot) and that is why a is b is True in the script but
not at the REPL.



You can see this behavior in the REPL too, if you wrap your statements in a function:



>>> import dis
>>> def foo():
... a = 300
... b = 300
... print(a==b)
... print(a is b)
... print("id(a) = %d, id(b) = %d" % (id(a), id(b)))
...
>>> foo()
True
True
id(a) = 4369383056, id(b) = 4369383056
>>> dis.disassemble(foo.__code__)
2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)
# snipped...


Bottom line: while CPython makes these optimizations at times, you shouldn't really count on it--it's really an implementation detail, and one that they've changed over time (CPython used to only do this for integers up to 100, for example). If you're comparing numbers, use ==. :-)






share|improve this answer

























  • This answer leaves a lot to be desired: by "tweaking the script" you're putting the code into a function scope (local vars) instead of a module scope (global vars), which - in terms of execution and name resolution - is now a completely different scoping situation. I think that somewhat invalidates the disassembly. Yes, it happens that the same peephole optimizer is used over the module code in the same way it's used over a function body, but that certainly doesn't have to be the case. And the answer also hasn't really explained why the same optimization is not done directly at the REPL.

    – wim
    Mar 26 at 15:51












  • @wim I certainly delete the answer if you don't think it meets the mark. I personally don't feel the tweaking was negative, but I hear you--it's not exactly the same. But I think all of this is pretty tied to what Python does today and isn't a guarantee of what Python may do in the future. And that's a fair criticism--I did not explicitly state why line by line at the REPL is different.

    – John Szakmeister
    Mar 26 at 16:55











  • Oh, I don't think you should delete it, just update it! I do think the disassembly demonstration is useful content. However, it should dis module scoped code, not function scoped code - recent versions of dis allow you to pass in a string of source directly, so it's not necessary to use a function object's __code__ attribute.

    – wim
    Mar 26 at 17:16












  • @wim That doesn't seem very fair to you--I think you've done the work on that front already and your answer should be the accepted answer (though I think adding the interning of small integers to the answer is good, just in case people try and get results they don't expect).

    – John Szakmeister
    Mar 27 at 21:09













Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "1"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55347581%2fwhy-does-the-is-operator-behave-differently-in-a-script-vs-the-repl%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









6














When you run code in a .py script, the entire file is compiled into a code object before executing it. In this case, CPython is able to make certain optimizations - like reusing the same instance for the integer 300.



You could also reproduce that in the REPL, by executing code in a context more closely resembling the execution of a script:



>>> source = """ 
... a = 300
... b = 300
... print (a==b)
... print (a is b)## print True
... print ("id(a) = %d, id(b) = %d"%(id(a), id(b))) ## They have same address
... """
>>> code_obj = compile(source, filename="myscript.py", mode="exec")
>>> exec(code_obj)
True
True
id(a) = 140736953597776, id(b) = 140736953597776


Some of these optimizations are pretty aggressive. You could modify the script line b = 300 changing it to b = 150 + 150, and CPython would still "fold" b into the same constant. If you're interested in such implementation details, look in peephole.c and Ctrl+F for the "consts table".



In contrast, when you run code line-by-line directly in the REPL it executes in a different context. Each line is compiled in "single" mode and this optimization is not available.



>>> scope = 
>>> lines = source.splitlines()
>>> for line in lines:
... code_obj = compile(line, filename="<I'm in the REPL, yo!>", mode="single")
... exec(code_obj, scope)
...
True
False
id(a) = 140737087176016, id(b) = 140737087176080
>>> scope['a'], scope['b']
(300, 300)
>>> id(scope['a']), id(scope['b'])
(140737087176016, 140737087176080)





share|improve this answer

























  • There is no optimization for b=150+150 in Python3.6, but with later versions.

    – ead
    Mar 26 at 20:56















6














When you run code in a .py script, the entire file is compiled into a code object before executing it. In this case, CPython is able to make certain optimizations - like reusing the same instance for the integer 300.



You could also reproduce that in the REPL, by executing code in a context more closely resembling the execution of a script:



>>> source = """ 
... a = 300
... b = 300
... print (a==b)
... print (a is b)## print True
... print ("id(a) = %d, id(b) = %d"%(id(a), id(b))) ## They have same address
... """
>>> code_obj = compile(source, filename="myscript.py", mode="exec")
>>> exec(code_obj)
True
True
id(a) = 140736953597776, id(b) = 140736953597776


Some of these optimizations are pretty aggressive. You could modify the script line b = 300 changing it to b = 150 + 150, and CPython would still "fold" b into the same constant. If you're interested in such implementation details, look in peephole.c and Ctrl+F for the "consts table".



In contrast, when you run code line-by-line directly in the REPL it executes in a different context. Each line is compiled in "single" mode and this optimization is not available.



>>> scope = 
>>> lines = source.splitlines()
>>> for line in lines:
... code_obj = compile(line, filename="<I'm in the REPL, yo!>", mode="single")
... exec(code_obj, scope)
...
True
False
id(a) = 140737087176016, id(b) = 140737087176080
>>> scope['a'], scope['b']
(300, 300)
>>> id(scope['a']), id(scope['b'])
(140737087176016, 140737087176080)





share|improve this answer

























  • There is no optimization for b=150+150 in Python3.6, but with later versions.

    – ead
    Mar 26 at 20:56













6












6








6







When you run code in a .py script, the entire file is compiled into a code object before executing it. In this case, CPython is able to make certain optimizations - like reusing the same instance for the integer 300.



You could also reproduce that in the REPL, by executing code in a context more closely resembling the execution of a script:



>>> source = """ 
... a = 300
... b = 300
... print (a==b)
... print (a is b)## print True
... print ("id(a) = %d, id(b) = %d"%(id(a), id(b))) ## They have same address
... """
>>> code_obj = compile(source, filename="myscript.py", mode="exec")
>>> exec(code_obj)
True
True
id(a) = 140736953597776, id(b) = 140736953597776


Some of these optimizations are pretty aggressive. You could modify the script line b = 300 changing it to b = 150 + 150, and CPython would still "fold" b into the same constant. If you're interested in such implementation details, look in peephole.c and Ctrl+F for the "consts table".



In contrast, when you run code line-by-line directly in the REPL it executes in a different context. Each line is compiled in "single" mode and this optimization is not available.



>>> scope = 
>>> lines = source.splitlines()
>>> for line in lines:
... code_obj = compile(line, filename="<I'm in the REPL, yo!>", mode="single")
... exec(code_obj, scope)
...
True
False
id(a) = 140737087176016, id(b) = 140737087176080
>>> scope['a'], scope['b']
(300, 300)
>>> id(scope['a']), id(scope['b'])
(140737087176016, 140737087176080)





share|improve this answer















When you run code in a .py script, the entire file is compiled into a code object before executing it. In this case, CPython is able to make certain optimizations - like reusing the same instance for the integer 300.



You could also reproduce that in the REPL, by executing code in a context more closely resembling the execution of a script:



>>> source = """ 
... a = 300
... b = 300
... print (a==b)
... print (a is b)## print True
... print ("id(a) = %d, id(b) = %d"%(id(a), id(b))) ## They have same address
... """
>>> code_obj = compile(source, filename="myscript.py", mode="exec")
>>> exec(code_obj)
True
True
id(a) = 140736953597776, id(b) = 140736953597776


Some of these optimizations are pretty aggressive. You could modify the script line b = 300 changing it to b = 150 + 150, and CPython would still "fold" b into the same constant. If you're interested in such implementation details, look in peephole.c and Ctrl+F for the "consts table".



In contrast, when you run code line-by-line directly in the REPL it executes in a different context. Each line is compiled in "single" mode and this optimization is not available.



>>> scope = 
>>> lines = source.splitlines()
>>> for line in lines:
... code_obj = compile(line, filename="<I'm in the REPL, yo!>", mode="single")
... exec(code_obj, scope)
...
True
False
id(a) = 140737087176016, id(b) = 140737087176080
>>> scope['a'], scope['b']
(300, 300)
>>> id(scope['a']), id(scope['b'])
(140737087176016, 140737087176080)






share|improve this answer














share|improve this answer



share|improve this answer








edited Mar 25 at 23:59

























answered Mar 25 at 23:39









wimwim

176k58 gold badges345 silver badges475 bronze badges




176k58 gold badges345 silver badges475 bronze badges












  • There is no optimization for b=150+150 in Python3.6, but with later versions.

    – ead
    Mar 26 at 20:56

















  • There is no optimization for b=150+150 in Python3.6, but with later versions.

    – ead
    Mar 26 at 20:56
















There is no optimization for b=150+150 in Python3.6, but with later versions.

– ead
Mar 26 at 20:56





There is no optimization for b=150+150 in Python3.6, but with later versions.

– ead
Mar 26 at 20:56













4














There are actually two things to know about CPython and its behavior here.
First, small integers in the range of [-5, 256] are interned internally.
So any value falling in that range will share the same id, even at the REPL:



>>> a = 100
>>> b = 100
>>> a is b
True


Since 300 > 256, it's not being interned:



>>> a = 300
>>> b = 300
>>> a is b
False


Second, is that in a script, literals are put into a constant section of the
compiled code. Python is smart enough to realize that since both a and b
refer to the literal 300 and that 300 is an immutable object, it can just
go ahead and reference the same constant location. If you tweak your script
a bit and write it as:



def foo():
a = 300
b = 300
print(a==b)
print(a is b)
print("id(a) = %d, id(b) = %d" % (id(a), id(b)))


import dis
dis.disassemble(foo.__code__)


The beginning part of the output looks like this:



2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)

...


As you can see, CPython is loading the a and b using the same constant slot.
This means that a and b are now referring to the same object (because they
reference the same slot) and that is why a is b is True in the script but
not at the REPL.



You can see this behavior in the REPL too, if you wrap your statements in a function:



>>> import dis
>>> def foo():
... a = 300
... b = 300
... print(a==b)
... print(a is b)
... print("id(a) = %d, id(b) = %d" % (id(a), id(b)))
...
>>> foo()
True
True
id(a) = 4369383056, id(b) = 4369383056
>>> dis.disassemble(foo.__code__)
2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)
# snipped...


Bottom line: while CPython makes these optimizations at times, you shouldn't really count on it--it's really an implementation detail, and one that they've changed over time (CPython used to only do this for integers up to 100, for example). If you're comparing numbers, use ==. :-)






share|improve this answer

























  • This answer leaves a lot to be desired: by "tweaking the script" you're putting the code into a function scope (local vars) instead of a module scope (global vars), which - in terms of execution and name resolution - is now a completely different scoping situation. I think that somewhat invalidates the disassembly. Yes, it happens that the same peephole optimizer is used over the module code in the same way it's used over a function body, but that certainly doesn't have to be the case. And the answer also hasn't really explained why the same optimization is not done directly at the REPL.

    – wim
    Mar 26 at 15:51












  • @wim I certainly delete the answer if you don't think it meets the mark. I personally don't feel the tweaking was negative, but I hear you--it's not exactly the same. But I think all of this is pretty tied to what Python does today and isn't a guarantee of what Python may do in the future. And that's a fair criticism--I did not explicitly state why line by line at the REPL is different.

    – John Szakmeister
    Mar 26 at 16:55











  • Oh, I don't think you should delete it, just update it! I do think the disassembly demonstration is useful content. However, it should dis module scoped code, not function scoped code - recent versions of dis allow you to pass in a string of source directly, so it's not necessary to use a function object's __code__ attribute.

    – wim
    Mar 26 at 17:16












  • @wim That doesn't seem very fair to you--I think you've done the work on that front already and your answer should be the accepted answer (though I think adding the interning of small integers to the answer is good, just in case people try and get results they don't expect).

    – John Szakmeister
    Mar 27 at 21:09















4














There are actually two things to know about CPython and its behavior here.
First, small integers in the range of [-5, 256] are interned internally.
So any value falling in that range will share the same id, even at the REPL:



>>> a = 100
>>> b = 100
>>> a is b
True


Since 300 > 256, it's not being interned:



>>> a = 300
>>> b = 300
>>> a is b
False


Second, is that in a script, literals are put into a constant section of the
compiled code. Python is smart enough to realize that since both a and b
refer to the literal 300 and that 300 is an immutable object, it can just
go ahead and reference the same constant location. If you tweak your script
a bit and write it as:



def foo():
a = 300
b = 300
print(a==b)
print(a is b)
print("id(a) = %d, id(b) = %d" % (id(a), id(b)))


import dis
dis.disassemble(foo.__code__)


The beginning part of the output looks like this:



2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)

...


As you can see, CPython is loading the a and b using the same constant slot.
This means that a and b are now referring to the same object (because they
reference the same slot) and that is why a is b is True in the script but
not at the REPL.



You can see this behavior in the REPL too, if you wrap your statements in a function:



>>> import dis
>>> def foo():
... a = 300
... b = 300
... print(a==b)
... print(a is b)
... print("id(a) = %d, id(b) = %d" % (id(a), id(b)))
...
>>> foo()
True
True
id(a) = 4369383056, id(b) = 4369383056
>>> dis.disassemble(foo.__code__)
2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)
# snipped...


Bottom line: while CPython makes these optimizations at times, you shouldn't really count on it--it's really an implementation detail, and one that they've changed over time (CPython used to only do this for integers up to 100, for example). If you're comparing numbers, use ==. :-)






share|improve this answer

























  • This answer leaves a lot to be desired: by "tweaking the script" you're putting the code into a function scope (local vars) instead of a module scope (global vars), which - in terms of execution and name resolution - is now a completely different scoping situation. I think that somewhat invalidates the disassembly. Yes, it happens that the same peephole optimizer is used over the module code in the same way it's used over a function body, but that certainly doesn't have to be the case. And the answer also hasn't really explained why the same optimization is not done directly at the REPL.

    – wim
    Mar 26 at 15:51












  • @wim I certainly delete the answer if you don't think it meets the mark. I personally don't feel the tweaking was negative, but I hear you--it's not exactly the same. But I think all of this is pretty tied to what Python does today and isn't a guarantee of what Python may do in the future. And that's a fair criticism--I did not explicitly state why line by line at the REPL is different.

    – John Szakmeister
    Mar 26 at 16:55











  • Oh, I don't think you should delete it, just update it! I do think the disassembly demonstration is useful content. However, it should dis module scoped code, not function scoped code - recent versions of dis allow you to pass in a string of source directly, so it's not necessary to use a function object's __code__ attribute.

    – wim
    Mar 26 at 17:16












  • @wim That doesn't seem very fair to you--I think you've done the work on that front already and your answer should be the accepted answer (though I think adding the interning of small integers to the answer is good, just in case people try and get results they don't expect).

    – John Szakmeister
    Mar 27 at 21:09













4












4








4







There are actually two things to know about CPython and its behavior here.
First, small integers in the range of [-5, 256] are interned internally.
So any value falling in that range will share the same id, even at the REPL:



>>> a = 100
>>> b = 100
>>> a is b
True


Since 300 > 256, it's not being interned:



>>> a = 300
>>> b = 300
>>> a is b
False


Second, is that in a script, literals are put into a constant section of the
compiled code. Python is smart enough to realize that since both a and b
refer to the literal 300 and that 300 is an immutable object, it can just
go ahead and reference the same constant location. If you tweak your script
a bit and write it as:



def foo():
a = 300
b = 300
print(a==b)
print(a is b)
print("id(a) = %d, id(b) = %d" % (id(a), id(b)))


import dis
dis.disassemble(foo.__code__)


The beginning part of the output looks like this:



2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)

...


As you can see, CPython is loading the a and b using the same constant slot.
This means that a and b are now referring to the same object (because they
reference the same slot) and that is why a is b is True in the script but
not at the REPL.



You can see this behavior in the REPL too, if you wrap your statements in a function:



>>> import dis
>>> def foo():
... a = 300
... b = 300
... print(a==b)
... print(a is b)
... print("id(a) = %d, id(b) = %d" % (id(a), id(b)))
...
>>> foo()
True
True
id(a) = 4369383056, id(b) = 4369383056
>>> dis.disassemble(foo.__code__)
2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)
# snipped...


Bottom line: while CPython makes these optimizations at times, you shouldn't really count on it--it's really an implementation detail, and one that they've changed over time (CPython used to only do this for integers up to 100, for example). If you're comparing numbers, use ==. :-)






share|improve this answer















There are actually two things to know about CPython and its behavior here.
First, small integers in the range of [-5, 256] are interned internally.
So any value falling in that range will share the same id, even at the REPL:



>>> a = 100
>>> b = 100
>>> a is b
True


Since 300 > 256, it's not being interned:



>>> a = 300
>>> b = 300
>>> a is b
False


Second, is that in a script, literals are put into a constant section of the
compiled code. Python is smart enough to realize that since both a and b
refer to the literal 300 and that 300 is an immutable object, it can just
go ahead and reference the same constant location. If you tweak your script
a bit and write it as:



def foo():
a = 300
b = 300
print(a==b)
print(a is b)
print("id(a) = %d, id(b) = %d" % (id(a), id(b)))


import dis
dis.disassemble(foo.__code__)


The beginning part of the output looks like this:



2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)

...


As you can see, CPython is loading the a and b using the same constant slot.
This means that a and b are now referring to the same object (because they
reference the same slot) and that is why a is b is True in the script but
not at the REPL.



You can see this behavior in the REPL too, if you wrap your statements in a function:



>>> import dis
>>> def foo():
... a = 300
... b = 300
... print(a==b)
... print(a is b)
... print("id(a) = %d, id(b) = %d" % (id(a), id(b)))
...
>>> foo()
True
True
id(a) = 4369383056, id(b) = 4369383056
>>> dis.disassemble(foo.__code__)
2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)

3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)
# snipped...


Bottom line: while CPython makes these optimizations at times, you shouldn't really count on it--it's really an implementation detail, and one that they've changed over time (CPython used to only do this for integers up to 100, for example). If you're comparing numbers, use ==. :-)







share|improve this answer














share|improve this answer



share|improve this answer








edited Mar 25 at 23:50

























answered Mar 25 at 23:44









John SzakmeisterJohn Szakmeister

29.9k7 gold badges64 silver badges65 bronze badges




29.9k7 gold badges64 silver badges65 bronze badges












  • This answer leaves a lot to be desired: by "tweaking the script" you're putting the code into a function scope (local vars) instead of a module scope (global vars), which - in terms of execution and name resolution - is now a completely different scoping situation. I think that somewhat invalidates the disassembly. Yes, it happens that the same peephole optimizer is used over the module code in the same way it's used over a function body, but that certainly doesn't have to be the case. And the answer also hasn't really explained why the same optimization is not done directly at the REPL.

    – wim
    Mar 26 at 15:51












  • @wim I certainly delete the answer if you don't think it meets the mark. I personally don't feel the tweaking was negative, but I hear you--it's not exactly the same. But I think all of this is pretty tied to what Python does today and isn't a guarantee of what Python may do in the future. And that's a fair criticism--I did not explicitly state why line by line at the REPL is different.

    – John Szakmeister
    Mar 26 at 16:55











  • Oh, I don't think you should delete it, just update it! I do think the disassembly demonstration is useful content. However, it should dis module scoped code, not function scoped code - recent versions of dis allow you to pass in a string of source directly, so it's not necessary to use a function object's __code__ attribute.

    – wim
    Mar 26 at 17:16












  • @wim That doesn't seem very fair to you--I think you've done the work on that front already and your answer should be the accepted answer (though I think adding the interning of small integers to the answer is good, just in case people try and get results they don't expect).

    – John Szakmeister
    Mar 27 at 21:09

















  • This answer leaves a lot to be desired: by "tweaking the script" you're putting the code into a function scope (local vars) instead of a module scope (global vars), which - in terms of execution and name resolution - is now a completely different scoping situation. I think that somewhat invalidates the disassembly. Yes, it happens that the same peephole optimizer is used over the module code in the same way it's used over a function body, but that certainly doesn't have to be the case. And the answer also hasn't really explained why the same optimization is not done directly at the REPL.

    – wim
    Mar 26 at 15:51












  • @wim I certainly delete the answer if you don't think it meets the mark. I personally don't feel the tweaking was negative, but I hear you--it's not exactly the same. But I think all of this is pretty tied to what Python does today and isn't a guarantee of what Python may do in the future. And that's a fair criticism--I did not explicitly state why line by line at the REPL is different.

    – John Szakmeister
    Mar 26 at 16:55











  • Oh, I don't think you should delete it, just update it! I do think the disassembly demonstration is useful content. However, it should dis module scoped code, not function scoped code - recent versions of dis allow you to pass in a string of source directly, so it's not necessary to use a function object's __code__ attribute.

    – wim
    Mar 26 at 17:16












  • @wim That doesn't seem very fair to you--I think you've done the work on that front already and your answer should be the accepted answer (though I think adding the interning of small integers to the answer is good, just in case people try and get results they don't expect).

    – John Szakmeister
    Mar 27 at 21:09
















This answer leaves a lot to be desired: by "tweaking the script" you're putting the code into a function scope (local vars) instead of a module scope (global vars), which - in terms of execution and name resolution - is now a completely different scoping situation. I think that somewhat invalidates the disassembly. Yes, it happens that the same peephole optimizer is used over the module code in the same way it's used over a function body, but that certainly doesn't have to be the case. And the answer also hasn't really explained why the same optimization is not done directly at the REPL.

– wim
Mar 26 at 15:51






This answer leaves a lot to be desired: by "tweaking the script" you're putting the code into a function scope (local vars) instead of a module scope (global vars), which - in terms of execution and name resolution - is now a completely different scoping situation. I think that somewhat invalidates the disassembly. Yes, it happens that the same peephole optimizer is used over the module code in the same way it's used over a function body, but that certainly doesn't have to be the case. And the answer also hasn't really explained why the same optimization is not done directly at the REPL.

– wim
Mar 26 at 15:51














@wim I certainly delete the answer if you don't think it meets the mark. I personally don't feel the tweaking was negative, but I hear you--it's not exactly the same. But I think all of this is pretty tied to what Python does today and isn't a guarantee of what Python may do in the future. And that's a fair criticism--I did not explicitly state why line by line at the REPL is different.

– John Szakmeister
Mar 26 at 16:55





@wim I certainly delete the answer if you don't think it meets the mark. I personally don't feel the tweaking was negative, but I hear you--it's not exactly the same. But I think all of this is pretty tied to what Python does today and isn't a guarantee of what Python may do in the future. And that's a fair criticism--I did not explicitly state why line by line at the REPL is different.

– John Szakmeister
Mar 26 at 16:55













Oh, I don't think you should delete it, just update it! I do think the disassembly demonstration is useful content. However, it should dis module scoped code, not function scoped code - recent versions of dis allow you to pass in a string of source directly, so it's not necessary to use a function object's __code__ attribute.

– wim
Mar 26 at 17:16






Oh, I don't think you should delete it, just update it! I do think the disassembly demonstration is useful content. However, it should dis module scoped code, not function scoped code - recent versions of dis allow you to pass in a string of source directly, so it's not necessary to use a function object's __code__ attribute.

– wim
Mar 26 at 17:16














@wim That doesn't seem very fair to you--I think you've done the work on that front already and your answer should be the accepted answer (though I think adding the interning of small integers to the answer is good, just in case people try and get results they don't expect).

– John Szakmeister
Mar 27 at 21:09





@wim That doesn't seem very fair to you--I think you've done the work on that front already and your answer should be the accepted answer (though I think adding the interning of small integers to the answer is good, just in case people try and get results they don't expect).

– John Szakmeister
Mar 27 at 21:09

















draft saved

draft discarded
















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f55347581%2fwhy-does-the-is-operator-behave-differently-in-a-script-vs-the-repl%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Kamusi Yaliyomo Aina za kamusi | Muundo wa kamusi | Faida za kamusi | Dhima ya picha katika kamusi | Marejeo | Tazama pia | Viungo vya nje | UrambazajiKuhusu kamusiGo-SwahiliWiki-KamusiKamusi ya Kiswahili na Kiingerezakuihariri na kuongeza habari

Swift 4 - func physicsWorld not invoked on collision? The Next CEO of Stack OverflowHow to call Objective-C code from Swift#ifdef replacement in the Swift language@selector() in Swift?#pragma mark in Swift?Swift for loop: for index, element in array?dispatch_after - GCD in Swift?Swift Beta performance: sorting arraysSplit a String into an array in Swift?The use of Swift 3 @objc inference in Swift 4 mode is deprecated?How to optimize UITableViewCell, because my UITableView lags

Access current req object everywhere in Node.js ExpressWhy are global variables considered bad practice? (node.js)Using req & res across functionsHow do I get the path to the current script with Node.js?What is Node.js' Connect, Express and “middleware”?Node.js w/ express error handling in callbackHow to access the GET parameters after “?” in Express?Modify Node.js req object parametersAccess “app” variable inside of ExpressJS/ConnectJS middleware?Node.js Express app - request objectAngular Http Module considered middleware?Session variables in ExpressJSAdd properties to the req object in expressjs with Typescript