Python 如何从内存地址加载 Python 对象

python 如何从内存地址上加载 pythn 对象

在 python 中我们可以通过 id 函数来获取某个 python 对象的内存地址,或者可以通过调用对象的__repr__魔术函数来获取对象的详细信息

def tt():
    print(111)
print(tt.__repr__())
print(id(tt))

但是不知大家是否想过,其实这个内存地址可以直接加载 python 对象的。有两种方法:

1. PyObj_FromPtr

在_ctypes 包中,就提供 PyObj_FromPtr 这个 api 去实现我们的需求。代码如下

def tt():
    print(111)
print(tt.__repr__())
print(_ctypes.PyObj_FromPtr(id(tt)))

运行结果如下:

<function tt at 0x106c628c8>
<function tt at 0x106c628c8>

2. gc.get_objects

我们也可以通过 gc 的 get_objects 方法来实现。先来看一下官方介绍

gc.get_objects()
Returns a list of all objects tracked by the collector, excluding the list returned.

大致意思为,获取所有可以追踪的对象。所以,我们可以通过第二种方式来实现从特定内存地址加载 python 对象

def tt():
    print(111)
print(tt.__repr__())

for i in gc.get_objects(): if id(i) == id(tt): print(i)

方法很简单,通过 gc.get_objects 获取所有对象,一一检查这些对象的内存地址是否与给定的内存地址相符,如果相符则返回对象。

结论

额,很扯淡的东西,最好不要乱用这种东西。因为出错的话,try except 语句都无法捕捉到这种异常。就当是了解一下吧


Python 如何从内存地址加载 Python 对象

1 回复

import ctypes

# 方法1:使用ctypes直接读取内存地址
def load_object_from_address(address):
    """
    从内存地址加载Python对象
    address: 整数形式的内存地址(如 id(obj) 返回的值)
    返回:对应的Python对象
    """
    # 将地址转换为ctypes指针
    obj_ptr = ctypes.cast(address, ctypes.py_object)
    # 获取指针指向的对象
    return obj_ptr.value

# 方法2:更安全的版本,带类型检查
def safe_load_from_address(address, expected_type=None):
    """
    安全地从内存地址加载对象,可指定期望类型
    address: 内存地址
    expected_type: 期望的对象类型(可选)
    """
    try:
        obj = load_object_from_address(address)
        if expected_type and not isinstance(obj, expected_type):
            raise TypeError(f"对象类型为 {type(obj)},不是期望的 {expected_type}")
        return obj
    except Exception as e:
        raise ValueError(f"无法从地址 {address} 加载对象: {e}")

# 使用示例
if __name__ == "__main__":
    # 创建一个测试对象
    test_list = [1, 2, 3, "hello"]
    
    # 获取对象的内存地址
    address = id(test_list)
    print(f"对象内存地址: {address} (0x{address:x})")
    
    # 从地址重新加载对象
    reloaded_list = load_object_from_address(address)
    print(f"重新加载的对象: {reloaded_list}")
    print(f"是同一个对象吗?: {reloaded_list is test_list}")
    
    # 修改原始对象
    test_list.append("world")
    print(f"修改后重新加载的对象: {reloaded_list}")
    
    # 安全加载示例
    try:
        safe_obj = safe_load_from_address(address, list)
        print(f"安全加载成功: {safe_obj}")
    except Exception as e:
        print(f"安全加载失败: {e}")

# 重要说明:
# 1. 这种方法只适用于当前Python进程中的对象
# 2. 如果对象已被垃圾回收,访问地址会导致段错误或未定义行为
# 3. 主要用于调试和特殊场景,日常编程中应避免使用

核心就两点:用ctypes.cast把地址转成指针,再用.value取对象。这玩意儿一般只在调试内存问题时用用,正常写代码别这么搞。

回到顶部