3

I have a function to retrieve an object in Python using the ctypes module:

import ctypes

def object_at_addr(obj_addr):
    try:
        val = ctypes.cast(obj_addr, ctypes.py_object).value
    except:
        return None
    return val

I know that the id of an object shows the memory address the object is at (for the most part as far as I've seen with builtins and custom objects). On my terminal shell, I tried this on the number 0 and "recursively" found the id of each number to see if it was cyclic in some form. Here is the terminal output:

>>> id(0) # num1
4343595216
>>> id(4343595216) # num2
4344636112
>>> id(4344636112) # num3
4344636112 

To my surprise, the id of two numbers were the same. However, when I use my function and call object_at_addr(4344636112), it doesn't point to either number, but instead returned a different int value as shown below:

>>> object_at_addr(4344636112)
4411205344

How can two different numbers have the same id value? Does the id function actually return the memory address for all objects, or is it only for custom objects, or is it just a Python design choice to make the memory address the id of an object, but it's different for builtin objects?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
succulentz
  • 70
  • 6
  • 3
    The integer objects `4343595216` and `4344636112` did not exist at the same time (they were eligible for garbage-collection as soon as `id()` returned), so there's absolutely nothing keeping Python from reusing the same memory address for the second one. (There's also absolutely nothing *requiring* Python to reuse the memory address.) – jasonharper Feb 12 '23 at 02:20
  • 1
    Does this answer your question? [How unique is Python's id()?](https://stackoverflow.com/questions/52096582/how-unique-is-pythons-id) – mkrieger1 Feb 12 '23 at 02:46
  • Does this answer your question? ["is" operator behaves unexpectedly with integers](https://stackoverflow.com/questions/306313/is-operator-behaves-unexpectedly-with-integers) – aneroid Feb 12 '23 at 03:19

1 Answers1

6

The id is always the memory address in the CPython implementation. The reason that you saw numbers with the same id here is that memory addresses can be re-used. The id is only guaranteed to be unique for the lifetime of the object, and since nothing else was holding a reference to the integer 4343595216 it got deleted immediately after the function call returns. That memory location was freed, and then immediately reused by the integer 4344636112 instance.

The docs actually mention this explicitly:

Two objects with non-overlapping lifetimes may have the same id() value.

wim
  • 338,267
  • 99
  • 616
  • 750