8

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.

3 Answers 3

10

Why it did not work

The object ctypes.cast(id(a), ctypes.py_object) provides a view to an object in memory. A view is an object in its own rights. So when updating the value attribute you do not update the object itself, all you do is create a new object and make the value attribute of your view 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

How to mutate any object

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.

Sign up to request clarification or add additional context in comments.

9 Comments

@user2357112 Which version of Python are you using, I cannot reproduce the error in your edit
2.7.11 on Windows.
I added the version since it seems to works for Python 3.6
I get a crash on Ideone as well, Python 3.5, apparently some flavor of Linux. Maybe try it in a fresh interpreter. It could have been affected by other things you did, like mutate(1, 2).
Yes, mutate(1, 2) is probably the cause since it makes Python exit with code -1073740940. My guess is that by mutating an integer, we may have mutated the exit code
|
2

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
>>>

Comments

0

use a list like this

>>> import ctypes
>>> a = ["hello world!"]
>>> ctypes.cast(id(a), ctypes.py_object).value[0] = "new value"
>>> print(a)
['new value']

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.