Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Updating a variable by its id within python

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.

like image 791
Kev1n91 Avatar asked Apr 15 '18 11:04

Kev1n91


People also ask

Can you update a variable in Python?

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.

Can you use ID as a variable in Python?

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.

What is updating variable in Python?

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.

How do you find the ID of a variable in Python?

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.


2 Answers

Why it did not work

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

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.

like image 57
Olivier Melançon Avatar answered Oct 03 '22 01:10

Olivier Melançon


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
>>>
like image 29
Maxime Chéramy Avatar answered Oct 03 '22 01:10

Maxime Chéramy