在python中通过其id更新变量

时间:2018-04-15 11:51:26

标签: python pointers ctypes

我知道如何通过Python中的id来获取变量的值,如:

a = "hello world!"
ctypes.cast(id(a), ctypes.py_object).value

我想知道是否可以用id覆盖变量值?

最简单的方法,这一个:

ctypes.cast(id(a), ctypes.py_object).value = "new value"

不起作用。

2 个答案:

答案 0 :(得分:3)

为什么它不起作用

对象ctypes.cast(id(a), ctypes.py_object)仅提供内存中对象的视图。因此,在更新value属性时,您不会更新对象本身,您只需创建一个新对象并使value指向它。

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

如何改变任何对象

可以使用ctypes直接更新内存,从而改变任何对象。对于被认为是不可变的字符串来说,情况确实如此。

以下内容很有趣,但在其他情况下不应使用 。除此之外,它还可以破坏对象引用计数,从而导致内存管理错误。

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]

以下是示例。在这些中你会找到你不能使用上述代码的理由,除非你真的知道你在做什么或作为一个练习。

s = 'Hello World!'
mutate(s, 'Bye World!!!')
print(s) # prints: 'Bye World!!!'

# The following happen because of Python interning
mutate('a', 'b')
print('a') # prints: 'b'

mutate(1, 2)
print(1) # prints: 2

特别是,上面的示例使Python退出时出现未知的错误代码或崩溃,具体取决于版本和环境。

答案 1 :(得分:2)

a是一个字符串,字符串在Python中是不可变的。

文档示例:

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