Please take a look at the following codes and explain what’s happening here:

a = 256
b = 256
a is b
#True its ok
c = 257
d = 257
c is d
#False why
e = 258; f=258;
e is f
//True 
// why?

Recommended Answers

All 6 Replies

They are all True on my computer as each pair points to the same address in memory (although I am on a 64 bit computer and it may be different on a 32 bit machine). Python keeps a list of objects for all "small" integers so they don't have several references to the same number in a program. When you create an int in that range you actually just get back a reference to the existing object. So each variable in the pair points to the same existing object. To get a False you would have to point to some calculated number i.e. it is not a reference to an existing object.

a = 256  ## lookup in existing list
b = 256
print a is b

c = 257
d = 257
print c is d

e = 258
f=258
print e is f

## create and put in unique memory location
## "256+1" not in list
g = 256+1
print "c is g", c is g, c, g

""" prints
True
True
True
c is g False 257 257
"""

Regarding your 3rd "why", Python performs certain primitive optimizations when it comes to immutable values. For when you write e=258; f=258 on the same line, Python realizes that it can save some space by making both variables point to the same value. This works not only for numbers but all immutable built-in types.

>>> a = 10.1
>>> b = 10.1
>>> a is b
False
>>> a = 10.1; b = 10.1
>>> a is b
True

But realize that this won't happen for mutable types since it results in change of semantics.

>>> a = []; b = []
>>> a is b
False

Again, implementation dependent but good to know I guess. :)

commented: Awesome! +14

I didn't know that, this is awesome. I don't think it is an optimisation, for example it does not work in functions

>>> def f():
...     a = 10.1
...     b = 10.1
...     print(a is b)
... 
>>> def g():
...     a = 10.1; b = 10.1
...     print(a is b)
... 
>>> f()
True
>>> g()
True
>>> 

I think it has to do with the fact that the interactive interpreter compiles each statement individually into a code object, so that when you write

>>> a = 10.1
>>> b = 10.1

two code objects are created and executed one after the other, and when you write

>>> a = 10.1; b = 10.1

a single code object is executed. These code objects contain a LOAD_CONST (bytecode) statement which loads the constant 10.1 on the stack. This constant is stored in an array aggregated to the code object. When 2 code objects are used, one has two different float objects, but when there is a single code object, the same float object is used.

In the case of functions f() and g() above, each function is compiled into a single code object, which means that a single float instance is used.

Edit: The following code confirms my theory

>>> def f():
...     x = 10.1
...     return x
... 
>>> f() is f()
True
>>> 
>>> def g():
...     x = 10.1
...     return x
... 
>>> f() is g()
False
>>> g() is g()
True

Yup, it's all about the evaluation context/scope. I call this an optimization because it is basically an implementation detail; a naive implementation doesn't have to do it and it will still work fine. I call it basic because it doesn't handle some other basic cases. For e.g. the below snippet

def f():
    a = (1, 2)
    b = (1, 2)
    print a is b

printf False even though (1,2) is a const. The VM could very well have taken care of this when compiling the function object but didn't.

A further look at the memory locations ...

>>> a = 10.1
>>> b = 10.1
>>> a is b
False
>>> c = 10.1; d = 10.1
>>> c is d
True
>>> id(a)
4298630584
>>> id(b)
4298631760
>>> id(c)
4298630704
>>> id(d)
4298630704
>>>

c = 10.1; d = 10.1 behaves more like c = d = 10.1

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.