Is the `id ()` variable associated with the value assigned to it after the variable has completed its life cycle?

I am doing object identification 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 '\nf - 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 throughout its entire life cycle, and that two objects with non-overlapping lifetimes can have the same id() value.

From this I understand that I can get the same id() at runtime for different variables, but I am surprised that in my code the same id() values ​​also match the values ​​of the variables.

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

So my question is: Does Python keep a record of previous variables, values, and identifiers even after their expiration?

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

I would like to learn a little about reusing id() values ​​and memory management in a Python program.

+4
source share
3 answers

The short answer to your question is that Python caches integers in the range [-5, 256].

Therefore, whenever you execute var1 = 10 or var1 = 1 , you always return the same object from the integer cache, and that is why you see the same id even in different runs of your function.

If you try to use values ​​greater than or equal to 257, you can see different results.

A very simple example of behavior is

 >>> var1 = 257 >>> var2 = 257 >>> id(var1) 36635792 >>> id(var2) 36636304 >>> var1 = 10 >>> var2 = 10 >>> id(var1) 1642386016 >>> id(var2) 1642386016 
+3
source

Another problem with the game is that the function caches all the constants in it.

Thus,

 def f(): return 1.1 assert f() is f() # or id(f()) == id(f()) 

You can find the cached constants associated with the function by looking at the code object.

 >>> print(f.__code__.co_consts) (None, 1.1) 

Typically, a tuple is a number, a string, or a tuple. Since you always assign the literal integer var1 , the compiler knows that it is a constant value that cannot be changed and therefore caches this integer object between function calls.

The reason I used float in f is because this is the only instance that the float will be stored in. Lines and integers can be cached in other circumstances, for example, for example.

 >>> x = 1.1 >>> y = 1.1 >>> x is y False 

Update

While tuples are considered immutable in Python, at the implementation level they represent another bit of mutable memory. Sometimes Python will mutate a tuple if it knows that no one else has access to the tuple. eg.

 >>> [id(x) for x in zip("abc", range(3))] [12684384, 48723328, 12684384] # different tuples >>> l = [] >>> for x in zip("abc", range(3)): l.append(id(x)) del x # only the zip iterator has access to yielded tuple now >>> l [12684384, 12684384, 12684384] 

See the corresponding lines for a zip on the following method .

 if (Py_REFCNT(result) == 1) { // if we are the only ref holder Py_INCREF(result); for (i=0 ; i < tuplesize ; i++) { it = PyTuple_GET_ITEM(lz->ittuple, i); item = (*Py_TYPE(it)->tp_iternext)(it); if (item == NULL) { Py_DECREF(result); return NULL; } olditem = PyTuple_GET_ITEM(result, i); PyTuple_SET_ITEM(result, i, item); // modify in place Py_DECREF(olditem); } 
+2
source

The documentation is correct, but the lifetime and object identifier can be a bit confusing. When assigning a variable (whether normal or extended), it means that the variable after it refers to the object on the right side of the assignment (which may be another object). For this reason, id(x) changes after assignment.

Please also note that the interpreter can store 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 available again.

For example, some (currently -5 to +256 believe) integers refer to such objects (therefore, before writing x=1 , object 1 already exists). Note that otherwise the same integer does not have to be the same (i.e. x==y does not mean that x is y ), which means there are redundant objects.

Another example is interned strings, usually the interpreter interprets strings for efficiency reasons (therefore, before writing x="keys" , the "keys" object already exists, because this one of the lines puts python).

Third example: objects can be created by reading compiled python code, which means that objects for numbers can be created even before the code starts execution. This means that whole literals and string literals with the same value will be the same object - if they are compiled at the same time.

Note that these are not mutable objects, so it won’t hurt you to get the same object again (since they are immutable, they will be equal regardless of whether they were created or reused).

+2
source

All Articles