【发布时间】:2018-04-15 11:51:25
【问题描述】:
我知道如何通过 Python 中的 id 获取变量的值,例如:
a = "hello world!"
ctypes.cast(id(a), ctypes.py_object).value
我想知道是否可以通过 id 覆盖变量值?
最简单的方法,这个:
ctypes.cast(id(a), ctypes.py_object).value = "new value"
不工作。
【问题讨论】:
我知道如何通过 Python 中的 id 获取变量的值,例如:
a = "hello world!"
ctypes.cast(id(a), ctypes.py_object).value
我想知道是否可以通过 id 覆盖变量值?
最简单的方法,这个:
ctypes.cast(id(a), ctypes.py_object).value = "new value"
不工作。
【问题讨论】:
对象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 happens because of Python interning
mutate('a', 'b')
print('a') # prints: 'b'
mutate(1, 2)
print(1) # prints: 2
特别是,上面的示例使 Python 退出时出现未知错误代码或崩溃,具体取决于版本和环境。
【讨论】:
mutate(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
>>>
【讨论】: