我在C++中编写Python 3扩展,我想找到一种方法来检查^ {< CD1>}是否与定义其实例布局的类型(Stult)有关。我只对静态大小PyObject
感兴趣,而不是{PyObject
头和(可选)用户定义成员。在
下面是基于众所周知的Noddy example in Defining New Types扩展的PyObject
示例:
// Noddy struct specifies PyObject instance layout
struct Noddy {
PyObject_HEAD
int number;
};
// type object corresponding to Noddy instance layout
PyTypeObject NoddyType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"noddy.Noddy", /*tp_name*/
sizeof(Noddy), /*tp_basicsize*/
0, /*tp_itemsize*/
...
Noddy_new, /* tp_new */
};
请注意,Noddy
是一种类型,一个编译时实体,
但是NoddyType
是运行时内存中的一个对象。
Noddy
和{tp_basicsize
成员中的sizeof(Noddy)
的值。在
Python中实现的手写继承指定了允许在PyObject
和用于声明该特定PyObject
的实例布局的类型之间转换的规则:
在类似于各种slot函数的情况下,可以安全地假设“Python对象是一个Noddy”并在不进行任何检查的情况下进行强制转换。 然而,有时需要在其他情况下施展,然后感觉像是盲目的转换:
void foo(PyObject* obj)
{
// How to perform safety checks?
Noddy* noddy = reinterpret_cast<Noddy*>(obj);
...
}
可以检查sizeof(Noddy) == Py_TYPE(obj)->tp_basicsize
,但由于以下原因,它是不够的解决方案:
1)如果用户将从Noddy
派生
class BabyNoddy(Noddy):
pass
并且obj
中的obj
指向BabyNoddy
的实例,Py_TYPE(obj)->tp_basicsize
是不同的。
但是,仍然可以安全地强制转换到reinterpret_cast<Noddy*>(obj)
以获取指向实例布局部分的指针。在
2)可以有其他结构声明与Noddy
大小相同的实例布局:
struct NeverSeenNoddy {
PyObject_HEAD
short word1;
short word2;
};
事实上,C语言级别的NeverSeenNoddy
结构与NoddyType
类型的对象兼容,它可以放入NoddyType
。所以,演员阵容可以很好。在
所以,我的大问题是:
是否有任何Python策略可用于确定PyObject
是否与Noddy
实例布局兼容?在
有什么方法可以检查PyObject*
是否指向嵌入在Noddy
中的对象部分?在
如果不是策略,是否有黑客攻击的可能?在
编辑:有几个问题看起来很相似,但在我看来,它们与我所问的不同。例如:Accessing the underlying struct of a PyObject
编辑2:为了理解我为什么把斯文·马纳赫的回答作为答案,请看下面的评论。在
在Python中,可以通过使用测试} :
isinstance(obj, Noddy)
来检查obj
是Noddy
类型还是派生类型。在C-API中测试某个PyObject *obj
是NoddyType
类型还是派生类型基本相同,可以使用^{至于你的第二个问题,没有办法做到这一点,如果你认为你需要这个,你的设计有严重的缺点。最好首先从
NoddyType
派生NeverSeenNoddyType
,然后上面的检查也会将派生类型的对象识别为NoddyType
的实例。在因为每个对象都以
PyObject_HEAD
开头,所以访问这个头定义的字段总是安全的。其中一个字段是ob_type
(通常使用Py_TYPE
宏访问)。如果这指向NoddyType
或从NoddyType
派生的任何其他类型(这是PyObject_IsInstance
告诉您的),那么您可以假定对象的布局是struct Noddy
。在换句话说,如果对象的
Py_TYPE
指向NoddyType
或其任何子类,则该对象与Noddy
实例布局兼容。在在第二个问题中,演员阵容不好。}的布局不同,即使大小可能相同。在
Noddy
和{假设
NeverSeenNoddy
是NeverSeenNoddy_Type
类型的布局,如果PyObject_IsInstance(obj, &NeverSeenNoddy_Type)
为false,则不应强制转换为NeverSeenNoddy
。在如果希望有两个具有公共字段的C级类型,则应该从实例布局中只有公共字段的公共基派生这两个类型。在
然后,子类型应在其布局顶部包含基础布局:
然后,如果
PyObject_IsInstance(obj, &SubNoddy_Type)
返回true,则可以强制转换到SubNoddy
并访问extra_field
字段。 如果PyObject_IsInstance(obj, &Noddy_Type)
返回true,则可以转换为Noddy
并访问公共字段。在相关问题 更多 >
编程相关推荐