The Built-In id() Function

by Christoph Schiessl on Python

In addition to equality, you can also compare objects in Python based on their identity. Object identities are represented by simple int values that you can retrieve using the built-in id(object) function. All Python objects, without exception, have a unique identity. The official documentation explains the id() function as follows:

Return the "identity" of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

So, all objects in existence at any given time have unique identities.

Python 3.12.2 (main, Feb 17 2024, 22:03:42) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> x, y = object(), object()
>>> id(x), id(y) # Two distinct objects have distinct identities.
(131886824916736, 131886824916784)
>>> id(x), id(y) # Identities never change => they are constant.
(131886824916736, 131886824916784)

So far, so good. The documentation explicitly said that the uniqueness of identities does not hold for objects whose lifetimes do not overlap, and this behavior is testable. Observe:

Python 3.12.2 (main, Feb 17 2024, 22:03:42) [GCC 13.2.1 20230801] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> prev_ids: set[int] = set()
>>> while True:
...     current_id: int = id(object())
...     if current_id in prev_ids:
...         print(f"Identity of the {len(prev_ids) + 1}th object was seen before!")
...         break
...     prev_ids.add(current_id)
Identity of the 2th object was seen before!

On my machine, the second object created had the same identity as the first one, which is no longer accessible (no references to it are in scope). This is implementation-specific, but if you use CPython, as I am, the first object has been garbage-collected. I can be sure of that because CPython object identities are nothing more than memory addresses. So, if the same memory address appears again for a different object, this must mean that the garbage collector has freed the object that previously occupied this memory address.

When I wrote this program, I didn't expect to get a repeated memory address for the second object, but it doesn't matter. The lifetime of the first object has ended, and therefore, the memory address it used to occupy is available for other objects. Second or not, the id() uniqueness, as required by the specification, has not been violated!

is and is not Operators

Object identities come into play when using the is operator. For instance, if you imagine two references, a and b, you can compare the identities of the objects behind these references with the expression a is b. This expression is equivalent to id(a) == id(b). So, it evaluates to True if a and b are the same object (they occupy the same memory address in CPython). Otherwise, it is evaluated to be False.

The is not operator is the negation of the is operator. So, the expression a is not b is equivalent to id(a) != id(b). Therefore, it evaluates to True if a and b are distinct objects (they occupy distinct memory addresses in CPython). Otherwise, it is evaluated to be False.

I hope you found this article helpful. Anyway, thank you very much for reading, and see you again next time!

Ready to Learn More Web Development?

Join my Mailing List to receive one article per week.

I send one email per week on building performant and resilient Web Applications with Python, JavaScript and PostgreSQL. No spam. Unscubscribe at any time.

Continue Reading?

Here are a few more Articles for you ...

The Built-In callable() Function

Learn about the callable() function in Python. This article explains how everything in Python is potentially callable, including classes and instances.

By Christoph Schiessl on Python

The Built-In bool() Class

Learn about boolean values in Python and the standard truth testing procedure. Understand how objects are converted to True or False.

By Christoph Schiessl on Python

Boolean Operators and Short-Circuiting

Fully understand Python's boolean operators for negation, conjunction, and disjunction. Master operator precedence and short-circuiting.

By Christoph Schiessl on Python

Christoph Schiessl

Hi, I'm Christoph Schiessl.

I help you build robust and fast web applications.

I'm available for hire as a freelance web developer, so you can take advantage of the more than a decade of experience I have collected working on many projects across several industries. Most of my clients are building web-based SaaS applications in a B2B context and depend on my expertise in various capacities.

More often than not, my involvement includes hands-on development work using technologies like Python, JavaScript, and PostgreSQL. Furthermore, if you already have an established team, I can support you as a technical product manager with a passion for simplifying complex processes. Lastly, I'm also an avid writer and educator who takes pride in breaking down technical concepts into the simplest possible terms.