Loading video player…

Object Value vs Object Identity

In Python, every object that is created is given a number that uniquely identifies it. It is guaranteed that no two objects will have the same identifier during any period in which their lifetimes overlap. Once an object’s reference count drops to zero and it is garbage collected, then its identifying number becomes available and may be used again.

The built-in Python function id() returns an object’s integer identifier. Using the id() function, you can verify that two variables indeed point to the same object.

00:00 Welcome to section 3, where we’ll talk about object identity. This is still part of our deeper dive, where we see a bit of what is actually going on when we assign a variable in Python.

00:10 There’s a couple of points that I want to talk about. Most importantly, you will learn about what’s an object value versus what is an object’s identity.

00:19 And then we’re going to go a bit into the weeds. Small integer caching is a weird thing in Python that might trip you up, and I think it’s quite fun if you know about it, so you will learn about how does that work.

00:31 And I’ve also got a little challenge for you, a Python pub quiz question that you can work out by yourself, and there’s also some solutions provided. So, let’s get going. First of all, let’s look at what is an object’s value versus what is its identity. For this, I’m heading over to an IPython session. It’s a new one, and so I’ll assign again the variables that we’ve worked with before.

00:56 n = 300 and m = 400, let’s say.

01:02 So, the value of n is what I get when I just put it into the interpreter. This is its value, what it points to, the integer object it points to.

01:12 And it has the value of 300. Now, every object in Python has a certain identity. It has a place in memory where it lives, and we can figure out that place in memory by saying id() and then passing in either the object or the reference to the object. So this is just a long string of numbers, right?

01:30 But this tells us specifically where in memory does this object live. And this object, in that case, is the integer object 300. So, what we would expect… If I say n = 300, then I create an integer object 300. And I say m = 300, I create another integer object 300.

01:54 And they both point to different objects in memory. If I would say id(n), I get some kind of number, and if I say id(m), I get a different number, you see?

02:05 So this is just showing us that those are two different objects, two different integer objects. Now, what we can see here is that even though both n and m have the same value, they have different object identity.

02:20 The way that we compare for a value, whether it’s the same value, is with the double equal sign (==). I can say n == m. It gives a result True, because 300 is the same as 300, the value. However, we know that those are two different objects.

02:39 So if I say the id(n) == id(m), we’re getting False. So even though these two variables have the same value, they don’t have the same identity. And this is kind of what we would expect, all right? That makes sense. But now comes the weird part.

Avatar image for reblark

reblark on Dec. 10, 2019

Everything in Python is an object—is a variable an object? I know that it points to an assigned value which is an object, but is it an object?

Avatar image for Martin Breuss

Martin Breuss RP Team on Dec. 10, 2019

Hehe, philosophical! No, a variable is a reference to an object, not an object itself. Like the shadows on Plato’s cave wall 😜…

Avatar image for reblark

reblark on Dec. 11, 2019

I suspected as much, but your statement is “everything in Python is an object.” A variable is a thing. Picky, picky, picky. BTW, I didn’t know there were shadows on Plato’s cave wall. Are you sure? Maybe at the entrance. :-)

Avatar image for Martin Breuss

Martin Breuss RP Team on Dec. 14, 2019

Almost. A variable is a reference to a thing. A variable itself doesn’t have a memory location (it’s not “a thing”) but only points to a thing (=an object).

Maybe we could agree on “Everything in Python that has a memory location is an object”–but I think that does sound less catchy!

There are shadows in Plato’s cave–but I don’t think the allegory to variables and objects holds that well apart from that.

Avatar image for John T

John T on Jan. 13, 2020

Hi I’m a bit confused with the example . My understanding has always been that all variables that reference the same value will have the same id. i.e if n =300 and m=300 then id(n) == id(m) will be True.

Avatar image for John T

John T on Jan. 13, 2020

pls ignore my last comment guys

Avatar image for kingjay2498

kingjay2498 on March 12, 2020

I am bit confused, Need help! if two object ids are different in memory , but has the same Object VALUE shouldnt objects ids be different right?

For example : n = 300 m = 300 # object ids are different , yet the object value is the same print(id(n)) print(id(m))

In your videos when you ran code the object ids were different ,

but when I use your example an ran code the object ids were the exact same , why is that? I dont get it my example: n = 300 m = 300 print(id(n)) print(id(m))

also when I compare both object ids the answer came back TRUE instead of false ? Confused ? Can anybody help me!:/

Avatar image for kingjay2498

kingjay2498 on March 12, 2020

In referring to my last comment objects ids keep popping up the same 1887265792816 1887265792816

Avatar image for Martin Breuss

Martin Breuss RP Team on March 12, 2020

It might be related to your Python version @kingjay2498. Make sure to check the excellent comments in the upcoming video section. Hope that helps to shed some light on your particular situation.

Avatar image for Ajay

Ajay on May 24, 2020

Hi Team, I was trying same example in my interpreter and got below different outputs:

ipython

In [1]: n = 300

In [2]: m = 400

In [3]: id(n)
Out[3]: 83420736

In [4]: id(m)
Out[4]: 83420912

In [5]: n = 300

In [6]: m = 300

In [7]: id(n)
Out[7]: 83420928

In [8]: id(m)
Out[8]: 83420768

User editor thonny

n = 300
m = 400
# id tells where object lives in memory
print (f"id of n {id(n)}")
print (f"id of m {id(m)}")
n = 300
m = 300
# id tells where object lives in memory
print (f"id of n {id(n)}")
print (f"id of m {id(m)}")

Output id of n 69962880 id of m 69963760 id of n 69962880 id of m 69962880

Now little confused that when i used ipython interpreter for different address for variable of same value and in editor got same value.

Avatar image for kiran

kiran on July 18, 2020

In [16]: a = 2

In [17]: b = 2

In [18]: id(a)
Out[18]: 8791518529216

In [19]: id(b)
Out[19]: 8791518529216

In [20]: a = 300

In [21]: b = 300

In [22]: id(a)
Out[22]: 84490864

In [23]: id(b)
Out[23]: 84489456

Why?

Avatar image for Martin Breuss

Martin Breuss RP Team on July 18, 2020

@manupanduworld just keep watching to the next video: realpython.com/lessons/small-integer-caching/ :)

Avatar image for Alain Rouleau

Alain Rouleau on July 26, 2020

Martin, not to disagree with you or Plato :-) … But the names/variables are indeed objects as well. If you use the dir() function it will return a list of names/variables in the local namespace, i.e. ['n', 'm', ...]

So, you actually have a “string object” pointing to an “integer object”. And each having a memory location as well. So, in Python everything truly is an object. :-)

As for Plato, the shadows on the cave walls are objects too and not simply references. You know, class Shadow() is composed of photons which in turn simply hit Plato’s eyeballs, LOL

Avatar image for Joseph Flanagan

Joseph Flanagan on Sept. 29, 2020

Following up on Alain Rouleau, isn’t a variable a key in the globals() dictionary?

>>> my_string = 'hello'

>>> globals()
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x110caac88>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__cached__': None, 'my_string': 'hello'}

>>> globals()['my_string']
'hello'

I’m not sure how this relates to the issue of names/variables as references to memory addresses, however.

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Sept. 30, 2020

There are a few built-in functions in Python that let you get a dictionary of variables:

As the name implies, calling globals() will only return the global variables. (It’ll skip variables defined in a function, for example.)

Regarding variables in Python, you can think of them as labels attached to objects. They’re like yellow stickers with names written on them, but apart from that, don’t have any type, value, or identity. These are attributes of a particular object a variable is pointing to, which can change over time. That isn’t true for other languages, where variables are more like cardboard boxes with a predefined shape and size.

Avatar image for DoubleA

DoubleA on Jan. 21, 2021

Hey there. Playing with the memory assingments. Here’s my code which when run:

m  = 100
n = m
print(id(n), id(m))  # print call 1

m = 400
print(id(n), id(m))  # print call 2

m = 'test'
print(id(n), id(m))  # print call 3

m = 400
(print(id(n), id(m)))  # print call 4

Produces the following output:

2961643492816 2961643492816 # same memory address, since n = m -> both refer to the same object
2961643492816 2961646790640 # diff. memory addresses, obviously
2961643492816 2961646716144 # reassignment, diff. memory addresses, logical
2961643492816 2961646790640 # the memory address of `m` becomes again the same as in the 2nd id() call. 

The above situation (see print calls 2 and 4) appears odd to me, since even though the object whose value was 400 (the variable m) was abandoned as a result of the reassignment m = 'test', its old memory address surfaced up in the last reassignment. This is despite the fact that the object 400 clearly wasn’t reachable until the reassignment (see the print call 4).

When I learned JS (sorry for bringing it in) the teaching was that those objects which can’t be reached are removed automatically from the memory as a result of the garbage collection process performed by the JS engine.

I haven’t checked the JS behaviour with the same code yet, but it seems that there are other conditions for an object to be collected as garbage than the mere fact that it can’t be reached.

Any comments on this?

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Jan. 22, 2021

@DoubleA According to the documentation, id() returns the object’s identity. Returning a memory address is a CPython implementation detail, which shouldn’t be relied upon.

In your case, it must have been a coincidence that the same piece of memory got reused for a different object. I couldn’t reproduce this behavior on my computer, which may very well depend on a specific Python interpreter build or even the operating system.

Avatar image for Bartosz Zaczyński

Bartosz Zaczyński RP Team on Jan. 22, 2021

By the way, I just noticed you are assigning the same numerical literal, which may trigger another quirk of CPython called interning.

Become a Member to join the conversation.