I know how to get the value of a variable by its id in Python like:
a = "hello world!"
ctypes.cast(id(a), ctypes.py_object).value
I wonder if it possible to overwrite the variables value by id?
The simplest way, this one:
ctypes.cast(id(a), ctypes.py_object).value = "new value"
does not work.
If you try to update a variable that doesn't exist, you get an error because Python evaluates the expression on the right side of the assignment operator before it assigns the resulting value to the name on the left. Before you can update a variable, you have to initialize it, usually with a simple assignment.
id() is a function in python, so it's recommend not to use a variable named id. Bearing that in mind, that applies to all functions that you might use... a variable shouldn't have the same name as a function.
One of the most common forms of multiple assignment is an update, where the new value of the variable depends on the old. This means “get the current value of x , add one, and then update x with the new value.” Updating a variable by adding 1 is called an increment; subtracting 1 is called a decrement.
The id() function returns an identity of an object. In Python, all variables or literal values are objects, and each object has a unique identity as an integer number that remains constant for that object throughout its lifetime.
The object ctypes.cast(id(a), ctypes.py_object)
only provides a view on an object in memory. So when updating the value
attribute you do not update the object itself, all you do is create a new object and make value
point to it.
import ctypes
a = "Hello World!"
py_obj = ctypes.cast(id(a), ctypes.py_object)
id(py_obj.value) # 1868526529136
py_obj.value = 'Bye Bye World!'
# Here we can see that `value` now points to a new object
id(py_obj.value) # 1868528280112
It is possible, with ctypes
, to update memory directly and thus to mutate any object. That is even true for strings which are said to be immutable.
The following is interesting as an exercice, but should never be used in other circumstances. Among other things it can corrupt object reference count, leading to memory management errors.
import ctypes
import sys
def mutate(obj, new_obj):
if sys.getsizeof(obj) != sys.getsizeof(new_obj):
raise ValueError('objects must have same size')
mem = (ctypes.c_byte * sys.getsizeof(obj)).from_address(id(obj))
new_mem = (ctypes.c_byte * sys.getsizeof(new_obj)).from_address(id(new_obj))
for i in range(len(mem)):
mem[i] = new_mem[i]
Here are examples. Among these you will find reasons why you must not use the above code unless you really know what you are doing or as an exercice.
s = 'Hello World!'
mutate(s, 'Bye World!!!')
print(s) # prints: 'Bye World!!!'
# The following happens because of Python interning
mutate('a', 'b')
print('a') # prints: 'b'
mutate(1, 2)
print(1) # prints: 2
In particular, the above example makes Python exit with an unknown error code or crash, depending on the version and environment.
a
is a string, and strings are immutable in Python.
Example from documentation:
>>> s = "Hello, World"
>>> c_s = c_wchar_p(s)
>>> print(c_s)
c_wchar_p(139966785747344)
>>> print(c_s.value)
Hello World
>>> c_s.value = "Hi, there"
>>> print(c_s) # the memory location has changed
c_wchar_p(139966783348904)
>>> print(c_s.value)
Hi, there
>>> print(s) # first object is unchanged
Hello, World
>>>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With