打印CPython对象的基础C结构表示

时间:2017-11-01 21:30:56

标签: python c python-3.x object struct

在幕后,任何Python对象都实现为带有一些字段的C结构。包含引用计数的16字节header和指向对象类型的指针始终存在于此结构上。这至少是64位股票CPython 3.x的情况,我的问题受到限制。

出于学术目的和它的乐趣,我正在寻找一个函数print_object(obj),它打印出传递的对象struct的基础obj

在实现方面,最简单的Python对象可能是float,它只是附加到前面提到的标头的C double。在这个简单的例子中,我已经能够使用ctypesstruct模块编写自己的这样的函数:

import collections, ctypes, struct, sys

header_fields = ['refcount', 'typeptr']
Float = collections.namedtuple('Float', header_fields + ['value'])

def print_object(obj):
    ptr = id(obj)
    size = sys.getsizeof(obj)
    byterep = ctypes.string_at(ptr, size)
    header = struct.unpack('qq', byterep[:16])
    if isinstance(obj, float):
        obj_struct = Float(*header, *struct.unpack('d', byterep[16:]))
    elif isinstance(obj, int):
        ...
    print(obj_struct)

# Try it out
a = 1.23
print_object(a)
print('The typeptr should be equal to', id(float))
print('\nNow the refcount should have increased by 1:')
b = a
print_object(a)

本质上,此函数读取对象的底层内存并构建C struct的副本作为Python namedtuple,有效地重新表示一段Python本身。代码应该在Python 3.5及更高版本上运行。它打印

  

Float(refcount = 5,typeptr = 140429307606720,value = 1.23)
   typeptr应该等于140429307606720

     

现在refcount应该增加1:
  Float(refcount = 6,typeptr = 140429307606720,value = 1.23)

上面的print_object函数适用于float,同样的方法可以扩展到(我想?)所有其他类型。那里的任何库(或者甚至是Python标准库)都包含这样的功能吗?

1 个答案:

答案 0 :(得分:0)

尝试自动执行此操作的问题在于,没有通用的方法来获取Python类型的布局。哎呀,甚至没有一般的方法可以说出结构有多大。此外,使用class语句创建的类型对于它们的实例并不完全使用struct,尽管它们大多像结构一样工作。

您需要自己为要使用的任何类型提供结构定义,并且仍需要对intstr等类型进行自定义处理,并使用特别奇怪的表示形式。