Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the `id()` of a variable associated to the value assigned to it after the variable lifetime finishes?

I am tinkering with objects' identity in Python with the following code:

def f(var1):
    print 'Within f and BEFORE modification: var1= '+str(var1)+', id= '+str(id(var1))
    var1 = 10
    print 'Within f and AFTER modification: var1= '+str(var1)+', id= '+str(id(var1))

def f2(var1):
    print 'Within f and BEFORE modification: var1= '+str(var1)+', id= '+str(id(var1))
    var1 = 1
    print 'Within f and AFTER modification: var1= '+str(var1)+', id= '+str(id(var1))

def f3(var1):
    print 'Within f and BEFORE modification: var1= '+str(var1)+', id= '+str(id(var1))
    var1 = 10
    print 'Within f and AFTER modification: var1= '+str(var1)+', id= '+str(id(var1))


var = 5

print '\n f - var1=10:'
print 'BEFORE FUNCTION CALL: var= '+str(var)+', id= '+str(id(var))
f(var)
print 'AFTER FUNCTION: var= '+str(var)+', id= '+str(id(var))

print '\n f2 - var1=1:'
var = [4,3,1,6]
print 'BEFORE FUNCTION CALL: var= '+str(var)+', id= '+str(id(var))
f2(var)
print 'AFTER FUNCTION: var= '+str(var)+', id= '+str(id(var))

print '\n f3 - var1=10 again:'
var = 7
print 'BEFORE FUNCTION CALL: var= '+str(var)+', id= '+str(id(var))
f3(var)
print 'AFTER FUNCTION: var= '+str(var)+', id= '+str(id(var))

print '\n f2 - var1=1 again:'
var='a'
print 'BEFORE FUNCTION CALL: var= '+str(var)+', id= '+str(id(var))
f2(var)
print 'AFTER FUNCTION: var= '+str(var)+', id= '+str(id(var))

Output:

 f - var1=10:
BEFORE FUNCTION CALL: var= 5, id= 18089816
Within f and BEFORE modification: var1= 5, id= 18089816
Within f and AFTER modification: var1= 10, id= 18089696
AFTER FUNCTION: var= 5, id= 18089816

 f2 - var1=1:
BEFORE FUNCTION CALL: var= [4, 3, 1, 6], id= 23884720
Within f and BEFORE modification: var1= [4, 3, 1, 6], id= 23884720
Within f and AFTER modification: var1= 1, id= 18089912
AFTER FUNCTION: var= [4, 3, 1, 6], id= 23884720

 f3 - var1=10 again:
BEFORE FUNCTION CALL: var= 7, id= 18089768
Within f and BEFORE modification: var1= 7, id= 18089768
Within f and AFTER modification: var1= 10, id= 18089696
AFTER FUNCTION: var= 7, id= 18089768

 f2 - var1=1 again:
BEFORE FUNCTION CALL: var= a, id= 140350777144584
Within f and BEFORE modification: var1= a, id= 140350777144584
Within f and AFTER modification: var1= 1, id= 18089912
AFTER FUNCTION: var= a, id= 140350777144584

I understand that the identity of an object is guaranteed to be unique during the its lifetime, and that two objects with non-overlapping lifetimes may have the same id() value.

From that I understand that I can get the same id() during the execution of the code for different variables, but I am surprised that in my code the same id() values coincide also with the variable values.

I mean that I always get the same id() value for var1=10. The same happens with the assignment var1=1 that has its own id() value. Even doing this assignment in different functions returns the same id().

So my question is: Is Python keeping a record of previous variables, values and identities even after their lifetimes have expired?

If in the code there is a variable assignment with the same value as a previously expired variable, does Python check records of the previous expired variables in memory and give priority to use the same id() for the same memory values?

I would like to understand a little bit more about id() values reuse and the memory management in a Python program.

like image 268
jchanger Avatar asked Mar 15 '23 04:03

jchanger


2 Answers

Short answer for your question - Python caches the integers in the range [-5 , 256] .

So whenever you do var1 = 10 or var1 = 1 , you always get back the same object from the integer cache, and that is why you are seeing the same id even in different runs of your function.

If you try it out for values greater than or equal 257, you may be able to see different results.

A very simple example of the behavior -

>>> var1 = 257
>>> var2 = 257
>>> id(var1)
36635792
>>> id(var2)
36636304
>>> var1 = 10
>>> var2 = 10
>>> id(var1)
1642386016
>>> id(var2)
1642386016
like image 53
Anand S Kumar Avatar answered Apr 28 '23 08:04

Anand S Kumar


The documentation is correct, but the lifetime and object identity may confuse a bit. When assigning to a variable (be it normal or augmented) means that the variable after it refers to the object on the right side of the assignment (which may be another object). This is the reason why id(x) changes after the assignment.

Note also that the interpreter may keep references to objects behind your back which means that the lifetime of the object may be longer than expected (even as long as the lifetime of the interpreter in some cases), or created earlier than you expect. In some cases these objects may be accessed again.

For example some (currently -5 to +256 i believe) integers are among those objects (so before you write x=1 the object 1 already exists). Note that otherwise the equal integer need not be the same (ie x==y doesn't imply that x is y), which means there's redundant objects.

Another example is interned strings, normally strings are interned by the interpreter for efficiency reasons (so before you write x="keys" the object "keys" already existed, because that's one of the strings python interns).

A third example is that objects may be created upon reading compiled python code, which means that the objects for the numbers may be created even before the code starts to execute. That means integer literals and string literals with the same value would be the same object - given that they're compiled at the same time.

Note that these are non-mutable objects so it would not hurt that you happen to get the same object again (since they are immutable they would be equal no matter if they were newly created or reused).

like image 25
skyking Avatar answered Apr 28 '23 06:04

skyking