在幕后,任何Python对象都实现为带有一些字段的C结构。包含引用计数的16字节header和指向对象类型的指针始终存在于此结构上。这至少是64位股票CPython 3.x的情况,我的问题受到限制。
出于学术目的和它的乐趣,我正在寻找一个函数print_object(obj)
,它打印出传递的对象struct
的基础obj
。
在实现方面,最简单的Python对象可能是float
,它只是附加到前面提到的标头的C double
。在这个简单的例子中,我已经能够使用ctypes
和struct
模块编写自己的这样的函数:
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标准库)都包含这样的功能吗?
答案 0 :(得分:0)
尝试自动执行此操作的问题在于,没有通用的方法来获取Python类型的布局。哎呀,甚至没有一般的方法可以说出结构有多大。此外,使用class
语句创建的类型对于它们的实例并不完全使用struct
,尽管它们大多像结构一样工作。
您需要自己为要使用的任何类型提供结构定义,并且仍需要对int
和str
等类型进行自定义处理,并使用特别奇怪的表示形式。