我正在尝试修改Brandon Rhodes代码
Routines that examine the internals of a CPython dictionary,以便它适用于cpython 3.3.
我相信我已成功翻译了这个结构.
typedef PyDictKeyEntry *(*dict_lookup_func) (PyDictObject *mp,PyObject *key,Py_hash_t hash,PyObject ***value_addr); struct _dictkeysobject { Py_ssize_t dk_refcnt; Py_ssize_t dk_size; dict_lookup_func dk_lookup; Py_ssize_t dk_usable; PyDictKeyEntry dk_entries[1]; };
我认为以下看起来很好:
from ctypes import Structure,c_ulong,POINTER,cast,py_object,CFUNCTYPE LOOKUPFUNC = CFUNCTYPE(POINTER(PyDictKeyEntry),POINTER(PyDictObject),POINTER(POINTER(py_object))) class PyDictKeysObject(Structure): """A key object""" _fields_ = [ ('dk_refcnt',c_ssize_t),('dk_size',('dk_lookup',LOOKUPFUNC),('dk_usable',('dk_entries',PyDictKeyEntry * 1),] PyDictKeysObject._dk_entries = PyDictKeysObject.dk_entries PyDictKeysObject.dk_entries = property(lambda s: cast(s._dk_entries,POINTER(PyDictKeyEntry * s.dk_size))[0])
这行代码现在有效,其中d == {0:0,1:1,2:2,3:3}:
obj = cast(id(d),POINTER(PyDictObject)).contents # works!!`
这是我在C struct PyDictObject中的翻译:
class PyDictObject(Structure): # an incomplete type """A dictionary object.""" def __len__(self): """Return the number of dictionary entry slots.""" pass def slot_of(self,key): """Find and return the slot at which `key` is stored.""" pass def slot_map(self): """Return a mapping of keys to their integer slot numbers.""" pass PyDictObject._fields_ = [ ('ob_refcnt',('ob_type',c_void_p),('ma_used',('ma_keys',POINTER(PyDictKeysObject)),('ma_values',POINTER(py_object)),# points to array of ptrs ]
解决方法
我的问题是访问cpython 3.3中实现的python字典的C结构.我开始使用cpython / Objects / dictobject.c和Include / dictobject.h中提供的C结构.定义字典涉及三个C结构:PyDictObject,PyDictKeysObject和PyDictKeyEntry.每个C结构到python的正确转换如下.评论表明我需要修复的地方.感谢@eryksun指导我一路走来!
class PyDictKeyEntry(Structure): """An entry in a dictionary.""" _fields_ = [ ('me_hash',c_ulong),('me_key',py_object),('me_value',] class PyDictObject(Structure): """A dictionary object.""" pass LOOKUPFUNC = CFUNCTYPE(POINTER(PyDictKeyEntry),POINTER(POINTER(py_object))) class PyDictKeysObject(Structure): """An object of key entries.""" _fields_ = [ ('dk_refcnt',# a function prototype per docs ('dk_usable',# an array of size 1; size grows as keys are inserted into dictionary; this variable-sized field was the trickiest part to translate into python ] PyDictObject._fields_ = [ ('ob_refcnt',# Py_ssize_t translates to c_ssize_t per ctypes docs ('ob_type',# Could not find this in the docs ('ma_used',# Py_Object* translates to py_object per ctypes docs ] PyDictKeysObject._dk_entries = PyDictKeysObject.dk_entries PyDictKeysObject.dk_entries = property(lambda s: cast(s._dk_entries,POINTER(PyDictKeyEntry * s.dk_size))[0]) # this line is called every time the attribute dk_entries is accessed by a PyDictKeyEntry instance; it returns an array of size dk_size starting at address _dk_entries. (POINTER creates a pointer to the entire array; the pointer is dereferenced (using [0]) to return the entire array); the code then accesses the ith element of the array)
以下函数提供对python字典底层的PyDictObject的访问:
def dictobject(d): """Return the PyDictObject lying behind the Python dict `d`.""" if not isinstance(d,dict): raise TypeError('cannot create a dictobject from %r' % (d,)) return cast(id(d),POINTER(PyDictObject)).contents
如果d是具有键值对的python字典,则obj是包含键值对的PyDictObject实例:
obj = cast(id(d),POINTER(PyDictObject)).contents
PyDictKeysObject的一个实例是:
key_obj = obj.ma_keys.contents
指向存储在字典的插槽0中的密钥的指针是:
key_obj.dk_entries[0].me_key
使用这些类的程序以及探测插入到字典中的每个键的哈希冲突的例程位于here.我的代码是由Brandon Rhodes为python 2.x编写的代码的修改.他的代码是here.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。