Issue
This is the common example for string immutability
>>> s1='Robert'
...
>>> id(s1)
...
2039784292400
>>> s1.replace('R','B')
...
'Bobert'
>>> id(s1)
...
2039784292400
>>> s1
...
'Robert'
Is there a way to find the id of the object holding the value 'Bobert'?
Edit: I do know I can assign it to another variable. I was wondering if there is a default object where such values are stored and if it is possible to get the id of such objects.
Solution
The short answer:
There is not a 'default object' into which Python interpreter stores values (memory addresses) which have not been assigned.
But rather, the interpreter executes a statement (for example s1.replace('R', 'B')
) and stores the result ('Bobert'
) into a memory location; which can be viewed as: id(s1.replace('R', 'B'))
. However, as there are no references pointing to that memory location - when garbage collection time comes - any unlinked references are deleted, thus freeing the memory for later use.
Worked example:
import ctypes
# Create the initial string object.
s1 = 'Robert'
s1_addr = id(s1)
print(f'{s1=} {s1_addr=}')
# Get the memory address to which the replacement points.
s2_addr = id(s1.replace('R', 'B'))
print(f'{s2_addr=}')
# Display (memory address) reference counts for each address.
s1_refs = ctypes.c_long.from_address(s1_addr).value
s2_refs = ctypes.c_long.from_address(s2_addr).value
print(f'{s1_refs=} {s2_refs=}')
Output:
s1='Robert' s1_addr=139940475739184
s2_addr=139940484802928
s1_refs=1 s2_refs=0
As you can see above, the s1
string is stored to a memory address. The replacement is also stored to a memory address. However, when it comes time to count the number of objects which point to each given address (as garbage collection will do), there are no references (objects) pointing to s2_addr
, so the memory will be freed when gc is called.
Digging a little deeper:
If you refer to the bytecode for the following statements:
# Not using assignment.
s1 = "Robert"; s1.replace("R", "B")
# Using assignment.
s1 = "Robert"; s2 = s1.replace("R", "B")
You'll note the following:
>>> dis('s1 = "Robert"; s1.replace("R", "B")'
1 0 LOAD_CONST 0 ('Robert')
2 STORE_NAME 0 (s1)
4 LOAD_NAME 0 (s1)
6 LOAD_METHOD 1 (replace)
8 LOAD_CONST 1 ('R')
10 LOAD_CONST 2 ('B')
12 CALL_METHOD 2 # <-- str.replace called.
# <-- No reference created.
14 POP_TOP
16 LOAD_CONST 3 (None)
18 RETURN_VALUE
You'll note the str.replace
method was called and thus acted upon the string, however as the STORE_NAME
instruction was not called, an object reference is not created to its memory address.
In this example, note the call to STORE_NAME
:
>>> dis('s1 = "Robert"; s2 = s1.replace("R", "B")')
1 0 LOAD_CONST 0 ('Robert')
2 STORE_NAME 0 (s1)
4 LOAD_NAME 0 (s1)
6 LOAD_METHOD 1 (replace)
8 LOAD_CONST 1 ('R')
10 LOAD_CONST 2 ('B')
12 CALL_METHOD 2 # <-- str.replace called.
14 STORE_NAME 2 (s2) # <-- Object reference created here.
16 LOAD_CONST 3 (None)
18 RETURN_VALUE
Answered By - S3DEV
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.