riemann_lebesgue
riemann_lebesgue

Reputation: 329

python id() different behaviour within and outside a function

I was experimenting with id to understand default values in python

def f(x=5000):
    print(id(x))
    x=40000
    print(id(x))
    print()
    

f()

f()

This gives the output

2187265500336
2187265501488

2187265500336
2187265501488

I understand why the first print statements are the same. This is because the default value x is evaluated when the function is defined.

However, that in both cases the second print statement gives the same id is confusing me and I couldn't find an answer online elsewhere. Consider

a=100000
print(id(a))

a=400000
print(id(a))

a=100000
print(id(a))

a=400000
print(id(a))

this gives the output

2187265558768
2187265558608
2187265559440
2187265558032

What is causing the difference in the two cases? Inside the function, when we reassign the variable in different function calls, it gets the same id, yet when we reassign a variable to the same value as previously outside a function, this doesn't occur

EDIT in response to @Barmar's comment and the question linked understanding python id() uniqueness. I somewhat understand, but not fully. My best guess now would be (1) the memory is left free for future use as said in the comment (2) in the example below, there seems to be some underlying reason why the same memory gets assigned to x each time even when other memory is assigned. Is this because of caching optimisations,

Caching optimizations mean that you are not always guaranteed to get a new object in cases where one might naiively think one should, but this does not in any way violate the uniqueness guarantee of IDs. Builtin types like int and str may have some caching optimizations, but they follow exactly the same rules: If they are live at the same time, and their IDs are the same, then they are the same object.

def f(x=5000):
    print(id(x))
    c=23000
    d=12444
    x=40000

    w=23444

    print(id(x))
    print()
    

f()

f()
2187265559440
2187265559376

2187265559440
2187265559376

Here we assign several new variables, but each time the same id gets assigned to the variable x upon reassignment.

Regarding @dont just talk code's comment

It probably will, if you just try it a few more times.

I then tried this with the following, but the same result held when repeated a million times

def f(x=5000):
    id_1 = id(x)
    c=23000
    d=12444
    x=40000

    w=23444

    id_2 = id(x)
    return (id_1, id_2)

[f() for n in range(1000000)] == [f() for n in range(1000000)]
True

Upvotes: 0

Views: 131

Answers (1)

kaya3
kaya3

Reputation: 51037

Constants inside a function come from the function's code object's co_consts attribute.

>>> f.__code__.co_consts
(None, 40000)
>>> id(f.__code__.co_consts[1])
140572403241776
>>> f()
140572374132688
140572403241776

So the second int object with the value 40000 is also created at the function definition, not during the function call.

This is a CPython implementation detail, because all details about CPython bytecode and code objects are CPython implementation details.

Upvotes: 5

Related Questions