python - 关于 PyClass_Check 和 PyClass_IsSubclass 函数的一些混淆

标签 python c exception embed python-c-api

我在学习python embedded C编程时遇到过问题。

这是我的示例: 读缓冲区.c

#include "Python.h"

static PyObject* Test_IsInstance(PyObject* self, PyObject* args){
    PyObject* pTest = NULL;
    PyObject* pName = NULL;
    PyObject* moduleDict = NULL;
    PyObject* className = NULL;
    PyObject* pModule = NULL;

    pName = PyString_FromString("common");
    pModule = PyImport_Import(pName);
    if (!pModule){
        printf("can not find client.py\n");
        Py_RETURN_NONE;
    }

    moduleDict = PyModule_GetDict(pModule);
    if (!moduleDict){
        printf("can not get Dict\n");
        Py_RETURN_NONE;
    }

    className = PyDict_GetItemString(moduleDict, "Test");
    if (!className){
        printf("can not get className\n");
        Py_RETURN_NONE;
    }

    PyObject* subClassName = PyDict_GetItemString(moduleDict, "pyTest");
    if (! subClassName){
        printf("can not get subClassName\n");
    }
    int k = PyClass_IsSubclass(subClassName, className);
    if (!k){
        printf("pyTest is not subclass of Test\n");
    }

    int r = PyClass_Check(className);
    if (!r){
        printf("className is not a class\n");
    } else {
        printf("className is a class\n");
    }
    PyObject* pInsTest = PyInstance_New(className, NULL, NULL);
    PyObject_CallMethod(pInsTest, "py_printT", "()");

    int ok = PyArg_ParseTuple(args, "O", &pTest);
    if (!ok){
        printf("parse tuple error!\n");
        Py_RETURN_NONE;
    }
    if (!pTest){
        printf("can not get the instance from python\n");
        Py_RETURN_NONE;
    }

    PyObject_CallMethod(pTest, "py_print", "()"); 

    if (!PyObject_IsInstance(pTest, className)){
        printf("Not an instance for Test\n");
        Py_RETURN_NONE;
    } else {
        printf("an instance for Test\n");
    }
    Py_RETURN_NONE;
}
static PyMethodDef readbuffer[] = {
    {"testIns", Test_IsInstance, METH_VARARGS, "test for instance!"},
    {NULL, NULL}
};

void initReadBuf(){
    PyObject* m;
    m = Py_InitModule("ReadBuf", readbuffer);
}

通用.py

class Test(object):
  def __init__(self):
    print "Test class"
  def py_printT(self):
    print "Test py_print"

class pyTest(Test):
  def __init__(self):
    Test.__init__(self)
    print "pyTest class"
  def py_print(self):
    print "pyTest py_print"

客户端.py

from common import pyTest
import ReadBuf as rb

b = pyTest()
rb.testIns(b)

我在python2.7.2上执行时,结果:

Test class
pyTest class
pyTest is not subclass of Test
className is not a class
New instance error
pyTest py_print
an instance for Test

如果我在python2.4.5上执行,结果:

Test class
pyTest class
pyTest is not subclass of Test
className is not a class
New instance error
pyTest py_print
an instance for Test
Exception exceptions.SystemError: 'Objects/classobject.c:528: bad argument to internal     function' in 'garbage collection' ignored
Fatal Python error: unexpected exception during garbage collection
Aborted (core dumped)

我的问题:

  1. 为什么python2.4.5会抛出异常?

  2. 我定义pyTestTest的子类,为什么结果是pyTest不是Test<的子类?

  3. 为什么当我执行PyClass_Check 函数时,className 不再是一个类?

  4. 因为className已经不是类了,为什么我执行了PyObject_IsInstance,结果为真?

  5. 如果我像下面这样修改Test类的定义,结果是正常的,为什么?

    class Test:   # don't inherit object any more
    

最佳答案

问题是 PyClass_* 函数应该用于旧式类。 当您从 object 继承时,该类成为新式类,您应该使用 PyType_* 函数,列出 here .

即:

在新型实例上对 PyClass_* 函数的所有调用结果都是伪造的。然而,PyObject_IsInstance 适用于旧式和新式类,这解释了为什么它无论如何都会返回 True

显然将 class Test(object) 更改为 class Test “解决”了奇怪的行为,因为 Test 现在是一个旧式类您应该使用 PyClass_* 函数。

Python2.4 是相当老的 python 版本,可能 API 之间存在一些不一致。您应该为您使用的每个 python 版本重建 C 扩展。 (最新版本的 python 确实有一个稳定的 ABI,但我相信不是 python2.4)。

关于python - 关于 PyClass_Check 和 PyClass_IsSubclass 函数的一些混淆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21929143/

相关文章:

java - 如何知道何时抛出异常

c# - .NET4 中未观察到的任务异常

python - linux 命令产生 Python OSError : [Errno 2] No such file or directory

python - 从 Web 运行 Python 脚本

c - 在使用 fgets() 填充后,如何从我的字符串数组中删除换行符 "\n"?

c++ - Windows:如何让子进程在不关闭输入匿名管道的情况下读取它?

Python 正则表达式匹配或标记化

python - pyautogui typewrite() 写入 shell 而不是单击的输入/文档

javascript - 是否可以将 C 代码编译为 Javascript 代码?

java - 我可以简化这三个 catch block 吗?