Locked learning resources

Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Locked learning resources

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Small Integer Caching

What is small integer caching? Python caches small integers, which are integers between -5 and 256. These numbers are used so frequently that it’s better for performance to already have these objects available. So these integers will be assigned at startup. Then, each time you refer to one, you’ll be referring to an object that already exists.

00:00 I’ll put it for you under the title of small integer caching. Okay? Keep that in mind. And let’s take a look at what’s happening here.

00:09 If I say a = 30 and b = 30, so same thing as before, but we’re using 30 instead of 300. What we would expect is a == b to be True, which it is.

00:24 And the id(a) == id(b), remember that this points to the location of the object in memory, so we would expect that to be False. However, in Python this is True.

00:37 And that’s kind of weird and could trip you up at the beginning if you don’t know about small integer caching, which is the solution of “Why is this happening?” And very simply, Python caches small integers. So, what’s a small integer? In Python, a small integer is anything between -5 and 256.

00:55 Everything in there gets cached. Let’s talk about what that means. I’ll roll it up again from the beginning with a couple of slides.

01:04 So, what we did is we assigned n and m both to the value 300, but they were both pointing to different objects, right?

01:12 So n was pointing to an integer object 300 and m was pointing to a new, different integer object with the same value, also 300.

01:23 So that’s why if we said n == m we would get True, same value, and id(n) did not equal id(m). You see? It’s two different objects.

01:34 Now, what happened when I said n = 30 and m = 30 as well—so, same type of assignment? Python actually is pointing us to the same object.

01:45 The reason being this cache, the small integer cache. At startup of an interpreter session, Python simply creates the objects for all of the small integers from -5 up to 256. It already creates these integer objects simply because these numbers are used so frequently that it’s better for performance to already have the objects there and just make it every time refer to the same object.

02:10 So this is why id(a) and id(b)—in this case, because it’s 30, which is smaller than 256—is actually pointing to the exact same object in memory. We can check on its number, in that case.

02:26 This is its location in memory. It’s going to be different when I start off a new IPython interpreter session because these integer objects get created on startup.

02:37 So, this is interesting and important to remember, because what I noted here is that essentially what happens is the same as if we would assign m to n. We saw this graphic before—n pointing to 30 and m pointing to 30—when we did this type of assignment.

02:54 And this is what happens with small integers even if we assign them on different lines and you would expect them to create different objects.

03:02 So, important to remember: any integer from -5 to 256 is going to be just assigned at startup, and every time you would refer to it in your program, it’s going to refer to an already existing object.

03:15 Anything above that, 257 upwards—it’s going to create new integer objects. So that’s a bit weird, but it’s a fun thing to know and it’s going to help you if you ever want to be in a Python pub quiz—which is something that happened to me at the PyCon! We got this question, exactly this question, and we had a couple of minutes to solve it.

03:37 So I want to give this to you as a challenge, because it’s a fun thing to think about. And there’s also a nice explanation that is going to be linked down here under the video. So check it out, but give it a try first and see if you can solve this.

03:49 The question is: what is a going to be? Without running the program, can you figure out what is a going to be? Just try to think through it, the different steps in this for loop, and keep in mind what happens with small integers in Python. I hope you’ll have fun. And don’t check the solution too quickly—just give it a go.

Avatar image for DoubleA

DoubleA on Jan. 21, 2021

Hi there. Running the same code as in the video in a) VS code and in b) cmd and getting different results :)

Avatar image for microb1tch

microb1tch on Dec. 5, 2021

For the “pub quiz,” I figured that the final print(a) statement would output 257, which is what I got when I ran the code in interpretive Python.

Interestingly enough, it seems that when I assign multiple variables to the same value (where value > 256), using one line on the interpreter, something interesting happens - Python seems to create one object, to which both variable names refer. Example code:

x = 3000; y = 3000
x == y
True
x is y
True
id(x)
37560752
id(y)
37560752

This seems to be the same phenomenon others have observed. Maybe this is yet another optimization?

If I assign the values separately, I see the behavior I would expect given what I learned in the video - Python creates two different objects with the same value. Example code:

x = 3000
y = 3000
x == y
True
x is y
False
id(x)
37451488
id(y)
36512832

Incrementing the value for each variable by 1 does what I expect, whether I make the assignment on one line, or do so separately. In either case, Python creates new, unique objects for each incremented value.

Avatar image for microb1tch

microb1tch on Dec. 5, 2021

Re: my last point about incrementing by 1, I checked whether new/unique objects were created by using the equality (==) and identity (is) operators. The equality operator returned True, but the identity operator returned False, as expected.

I also checked this using the id() function. After the initial assignment statement, id() indicated that both variables referred to the same memory location (ie. they referred to the same object). After incrementing the variables, id(x) and id(y) returned unique numbers, suggesting that the incremented values were new, unique objects.

So it seems that if you do multiple assignment statements w/ the same value all at once (regardless of whether the integer is greater or less than 256), you create one object in one memory location, which has multiple references to it. But when you manipulate that object (eg. by incrementing its value), Python will create new objects for the changed values (whether you change the values all at once on one interpreter line, or do so on multiple lines w/ separate statements), which occupy different locations in memory than the original object.

It seems that Python copies the original integer object to a new location in memory when you manipulate it, rather than overwriting the area in memory it occupied. Presumably, the original value(s) (eg. the integer object 3000 that was created w/ the initial assignment statement in my first code example above) get taken out with the trash when Python collects the garbage, since they no longer have any references to them.

Avatar image for Martin Breuss

Martin Breuss RP Team on Dec. 6, 2021

Great investigative research on this topic @RheaRevolver and your conclusions all sound correct as far as my current knowledge of Python internals goes! :)

You might enjoy reading through the CPython Internals Book!

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Dec. 6, 2021

@RheaRevolver That’s correct. I briefly touched on it in a tutorial about the bitwise operators in Python.

Avatar image for jyotirmoyr1

jyotirmoyr1 on Feb. 11, 2022

Hi, For me in: Ubuntu 20..4.3 LTS Python version- 3.9.7 The result for below code is:

x=21
y=20
print('Is x==y, where x=21 and y=20 :', x==y) 
## results False
print('is id(x)==id(y),where x=21 and y=20  :',id(x)==id(y),id(x),id(y)) 
## Results False 
x=900
y=900
print()
print('Is x==y, where x=900 and y=900 :', x==y)
## results True
print('is id(x)==id(y),where x=900 and y=900  :',id(x)==id(y),id(x),id(y))
## results True

After going through the discussion list it seems that the results differ depending on Python version/Platform and the editor getting used.

Thanks, JR

Avatar image for jyotirmoyr1

jyotirmoyr1 on Feb. 11, 2022

More on this, the fun is when code written in a editor like VScode and running on terminal window giving result as True for bigger integers, but when running from Python interpreter it self the result is False. Why??

Thanks, JR

Avatar image for Kumar Abhishek

Kumar Abhishek on Aug. 28, 2022

@Martin the id’s for any variables storing any range of values are just the same.

Avatar image for Martin Breuss

Martin Breuss RP Team on Sept. 13, 2022

@Kumar Abhishek I’m not sure what you mean with this:

>>> a = range(100)
>>> b = range(200)

>>> id(a)
4375712320

>>> id(b)
4376351824

>>> id(a) == id(b)
False

Also not quite sure how it relates to the lesson. Could you try to explain your comment a bit more?

Avatar image for Valdemar

Valdemar on Dec. 22, 2022

I wanted to test out RheaRevolver’s point, so I ran this program:

a, b = 300, 300
c = 300
print(a is b is c)
print(id(a),id(b), id(c))


for _ in range(250, 260):
    if a is not b:
        break
    a += 1
    b += 1

print(a is b)
print(id(a),id(b))
print(a)

d = 300

print(id(c) is id(d))
print(id(c), id(d))

And it does seem, that a, b and c all point to the same object, but d points a different object, even though c remains unchanged. At least print(id(c) is id(d)) returns False. So it seems that assigning the same value at the same time means pointing to the same object, but assigning the same value at different times, points to a different object. However the final print statement returns the same address for the two objects.

I thought that was a little strange, so I wanted to share it. Does ‘is’ not compare the two addresses?

Become a Member to join the conversation.