C调用python类的正确方法

 

C或C++调用python一般都可以使用python自带的库完成,首先添加python.h的头文件,链接时加上对应的库即可。

但是在C/C++程序中使用到python的类时会遇到很多坑,网上搜会得到很多相似的方法如下所示

首先声明,以下的方法是有问题的,有问题的地方我会使用红字标出

注: 下述所有导入方法在导入失败时不会报错, 只会返回空指针.

第一步是导入.py文件:

  1. 使用PyObject* pModule来存储导入的.py文件模块, 调用的方法是PyImport_ImportModule(path):  PyObject* pModule = PyImport_ImportModule("testpy"); 
  2. 使用PyObject* pDict来存储导入模块中的方法字典, 调用的方法是PyModule_GetDict(module):  PyObject* pDict = PyModule_GetDict(pModule); 

这样就完成了.py文件的导入.

第二步是导入已导入模块中的方法或类:

  1. 获取方法, 调用的方法是PyDict_GetItemString(dict, methodName): PyObject* pFunHi = PyDict_GetItemString(pDict, "sayhi"); 
  2. 获取类, 调用的方法同上, 注意红体部分的字符串对应于.py文件中的类/方法名:  PyObject* pClassSecond = PyDict_GetItemString(pDict,"Second"); 

第三步是使用导入的方法或类:

  1. 使用方法, 调用PyObject_CallFunction(pFunc, "s", args)即可:  PyObject_CallFunction(pFunHi, "s", "lhb"); 
  2. 使用类构造对象, 调用PyInstance_New(pClass, NULL, NULL)即可:  PyObject* pInstanceSecond = PyInstance_New(pClassSecond, NULL, NULL); , 注意其中的pClassSecond为第二步.2中获取的类指针
  3. 使用类对象的方法, 调用PyObject_CallMethod(pInstance, methodname, "O", args)即可:  PyObject_CallMethod(pInstanceSecond,"invoke", "O", pInstancePerson); 
  4. 上述调用中的"s"和"O"代表的是参数列表的类型, 我们可以在 Py_BuildValue 找到所有的类型, 本文最后也附了此表.

PyInstance_New是python2使用的函数,python3则使用新的函数PyInstanceMethod_New,国内很多文章都认为这两个函数返回的是类的实例对象,其实不然,它们返回的是该类的构造函数对象

按照上面文章的步骤做在不涉及修改类的成员变量时是没有问题的,如果有python类

class Test:
    def __init__(self):
        self.i = 1
        print("init!")

    def modify(self):
        self.i+=1

    def do(self):
        print(self.i)

如果使用上面的方法使用这个类,调用do方法是不会有问题的,可以成功打印,但是如果调用modify则会报错,PyErr_Print打印错误信息则会提示i不存在。

并且在PyInstance_New或PyInstanceMethod_New时并不会打印init!,说明构造函数根本没有被调用。

正确的调用方式则应该是

PyObject* pConstruct = PyInstanceMethod_New(pClass);
PyObject* pIns = PyObject_CallObject(pConstruct,nullptr);
PyObject_CallMethod(pIns,"modify", nullptr); 
PyObject_CallMethod(pIns,"do", nullptr); 

使用PyInstanceMethod_New获得构造函数后才能构造对象,并且调用时不需要传递自身。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值