You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何打印Python数据类型内存结构 输出内部字段十六进制转储

可用现成方案

调试器内置工具(准确率最高)

如果可以用GDB/LLDB附加到Python进程,CPython源码自带的调试辅助脚本是最匹配需求的选择,和当前运行的Python版本结构体定义完全一致:

  • 原生支持解析所有内置类型的内部字段,包括引用计数、类型指针、变长对象长度、列表的allocated和ob_item、字典哈希表结构等所有内部细节
  • 自带递归解析引用对象的能力,可直接展示每个字段的内存地址、实际值
  • 不需要额外安装第三方库,只要调试环境的Python版本和运行版本匹配、带基础调试符号即可使用
    缺点是需要在调试器环境下操作,无法直接在普通Python代码中调用输出。

纯Python第三方库

目前没有完全匹配需求(同时实现结构体字段自动解析+格式化十六进制转储+递归展示引用对象)的成熟库,可组合使用以下接近的工具:

  • hexdump:专门做内存/字节串的格式化十六进制输出,输出格式和给出的示例完全一致,支持自定义每行字节数、偏移起始地址、ASCII展示列,传入内存起始地址和长度即可得到标准的十六进制转储内容。
  • objprint:可递归打印任意Python对象的内存地址、属性值、内部嵌套结构,支持自定义输出深度,但默认不输出原始十六进制内存内容,可以和hexdump组合使用补全内存转储能力。
  • pyinternals:面向教学场景的小型工具库,内置了常见CPython内置类型(int、str、list、dict、bytes等)的结构体定义,可以直接读取并打印对象头的引用计数、类型指针、各类型特有字段的值,缺点是更新不及时,对3.11+版本调整过的结构体(比如新版字符串、字典布局)支持不好,需要手动适配结构体定义。
自行实现的核心思路

如果要做适配自身Python版本、完全符合输出要求的工具,开发成本很低,核心步骤如下:

  1. 定义对应版本的CPython结构体:找到当前运行的CPython版本对应源码里的头文件(比如listobject.h、object.h、dictobject.h等),用ctypes.Structure按顺序定义对应字段,64位环境下Py_ssize_t对应c_ssize_t、指针对应c_void_p,ctypes默认内存对齐规则和CPython编译时一致即可。
    64位CPython 3.10环境下PyListObject的定义示例:

    from ctypes import Structure, c_ssize_t, c_void_p, POINTER
    
    class PyObject(Structure):
        _fields_ = [
            ("ob_refcnt", c_ssize_t),
            ("ob_type", c_void_p),
        ]
    
    class PyVarObject(Structure):
        _fields_ = [
            ("ob_base", PyObject),
            ("ob_size", c_ssize_t),
        ]
    
    class PyListObject(Structure):
        _fields_ = [
            ("ob_base", PyVarObject),
            ("ob_item", POINTER(c_void_p)),
            ("allocated", c_ssize_t),
        ]
    
  2. 实现通用十六进制转储函数:输入内存起始地址、长度,按每行16字节的格式输出偏移、十六进制字节、对应可打印ASCII字符即可,几十行代码就能实现,不需要依赖第三方库。

  3. 编写类型分发的递归解析逻辑:拿到任意对象的地址后,先转成对应类型的结构体指针,打印对象地址、引用计数、类型指针、类型特有字段,再根据类型递归解析其引用的其他对象(比如列表就遍历ob_item指向的指针数组,逐个解析每个元素),同时对每个对象的内存块调用十六进制转储函数输出原始内存内容。

    核心代码量一般在200行以内就能覆盖list、dict、str、int、bytes这些最常用的内置类型,足够用于教学和底层原理探究。

注意事项
  • 你当前写的示例代码存在缺陷:sys.getsizeof(a)只返回PyListObject结构体本身的大小,不包含ob_item指向的元素指针数组、以及元素对象本身占用的内存,所以只能打印列表头的内容,看不到元素指针和元素数据。
  • 只要保证转储过程中对象被正常持有(不会被GC回收),只读访问内存是完全安全的,不要随意修改内存内容就不会导致解释器崩溃。
  • 不同CPython大版本的结构体布局差异很大(比如3.11之后的字符串结构、3.12之后的字典结构都有调整),一定要用对应版本的头文件定义结构体,否则解析出来的字段值会出错。

内容的提问来源于stack exchange,提问作者martin's

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.31 13:01:20