日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > python >内容正文

python

如何在C++中调用python程序?

發(fā)布時(shí)間:2025/3/19 python 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何在C++中调用python程序? 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

      • 1. Embedding Python in Another Application 將Python嵌入另一個(gè)應(yīng)用程序中
        • 1.1. Very High Level Embedding 高層嵌入
        • 1.2. Beyond Very High Level Embedding: An overview 超越高級(jí)嵌入:概述
        • 1.3. Pure Embedding 純嵌入
        • 1.4. Extending Embedded Python
        • 1.5. Embedding Python in C++ 在C ++中嵌入Python
        • 1.6. Compiling and Linking under Unix-like systems 編譯和在類Unix系統(tǒng)鏈接

1. Embedding Python in Another Application 將Python嵌入另一個(gè)應(yīng)用程序中

The previous chapters discussed how to extend Python, that is, how to extend the functionality of Python by attaching a library of C functions to it. It is also possible to do it the other way around: enrich your C/C++ application by embedding Python in it. Embedding provides your application with the ability to implement some of the functionality of your application in Python rather than C or C++. This can be used for many purposes; one example would be to allow users to tailor the application to their needs by writing some scripts in Python. You can also use it yourself if some of the functionality can be written in Python more easily.

前面的章節(jié)討論了如何擴(kuò)展Python,即如何通過將C函數(shù)庫附加到Python來擴(kuò)展Python的功能。也可以通過其他方式做到這一點(diǎn):通過將Python嵌入到C / C ++應(yīng)用程序中來豐富它。嵌入為您的應(yīng)用程序提供了使用Python而非C或C ++實(shí)現(xiàn)應(yīng)用程序某些功能的能力。這可以用于許多目的。一個(gè)示例是允許用戶通過使用Python編寫一些腳本來根據(jù)自己的需求定制應(yīng)用程序。如果某些功能可以更輕松地用Python編寫,那么您也可以自己使用它。

Embedding Python is similar to extending it, but not quite. The difference is that when you extend Python, the main program of the application is still the Python interpreter, while if you embed Python, the main program may have nothing to do with Python — instead, some parts of the application occasionally call the Python interpreter to run some Python code.

嵌入Python與擴(kuò)展Python類似,但不完全相同。區(qū)別在于,當(dāng)您擴(kuò)展Python時(shí),應(yīng)用程序的主程序仍然是Python解釋器,而如果您嵌入Python,則主程序可能與Python無關(guān)—相反,應(yīng)用程序的某些部分有時(shí)會(huì)調(diào)用Python解釋器運(yùn)行一些Python代碼。

So if you are embedding Python, you are providing your own main program. One of the things this main program has to do is initialize the Python interpreter. At the very least, you have to call the function Py_Initialize(). There are optional calls to pass command line arguments to Python. Then later you can call the interpreter from any part of the application.

因此,如果您要嵌入Python,那么您將提供自己的主程序。這個(gè)主程序要做的一件事就是初始化Python解釋器。至少,您必須調(diào)用函數(shù)Py_Initialize()。有一些可選的調(diào)用,可將命令行參數(shù)傳遞給Python。然后,您可以從應(yīng)用程序的任何部分調(diào)用解釋器。

There are several different ways to call the interpreter: you can pass a string containing Python statements to PyRun_SimpleString(), or you can pass a stdio file pointer and a file name (for identification in error messages only) to PyRun_SimpleFile(). You can also call the lower-level operations described in the previous chapters to construct and use Python objects.

有幾種不同的調(diào)用解釋器的方式:可以將包含Python語句的字符串傳遞給PyRun_SimpleString(),或者可以將stdio文件指針和文件名(僅用于錯(cuò)誤消息中的標(biāo)識(shí))傳遞給PyRun_SimpleFile()。您還可以調(diào)用前面各章中描述的較低級(jí)別的操作來構(gòu)造和使用Python對(duì)象。

參見
Python/C API 參考手冊(cè)
The details of Python’s C interface are given in this manual. A great deal of necessary information can be found here.

1.1. Very High Level Embedding 高層嵌入

The simplest form of embedding Python is the use of the very high level interface. This interface is intended to execute a Python script without needing to interact with the application directly. This can for example be used to perform some operation on a file.

嵌入Python的最簡(jiǎn)單形式是使用非常高級(jí)的接口。該接口旨在執(zhí)行Python腳本,而無需直接與應(yīng)用程序進(jìn)行交互。例如,這可用于對(duì)文件執(zhí)行某些操作。

#define PY_SSIZE_T_CLEAN #include <Python.h>int main(int argc, char *argv[]) {wchar_t *program = Py_DecodeLocale(argv[0], NULL);if (program == NULL) {fprintf(stderr, "Fatal error: cannot decode argv[0]\n");exit(1);}Py_SetProgramName(program); /* optional but recommended */Py_Initialize();PyRun_SimpleString("from time import time,ctime\n""print('Today is', ctime(time()))\n");if (Py_FinalizeEx() < 0) {exit(120);}PyMem_RawFree(program);return 0; }

The Py_SetProgramName() function should be called before Py_Initialize() to inform the interpreter about paths to Python run-time libraries. Next, the Python interpreter is initialized with Py_Initialize(), followed by the execution of a hard-coded Python script that prints the date and time. Afterwards, the Py_FinalizeEx() call shuts the interpreter down, followed by the end of the program. In a real program, you may want to get the Python script from another source, perhaps a text-editor routine, a file, or a database. Getting the Python code from a file can better be done by using the PyRun_SimpleFile() function, which saves you the trouble of allocating memory space and loading the file contents.

Py_SetProgramName()在Py_Initialize()通知解釋器有關(guān)Python運(yùn)行時(shí)庫的路徑之前,應(yīng)先調(diào)用該函數(shù) 。接下來,使用初始化Python解釋器 Py_Initialize(),然后執(zhí)行打印日期和時(shí)間的硬編碼Python腳本。之后,該P(yáng)y_FinalizeEx()調(diào)用將關(guān)閉解釋器,然后結(jié)束程序。在實(shí)際程序中,您可能希望從其他來源(可能是文本編輯器例程,文件或數(shù)據(jù)庫)獲取Python腳本。使用該P(yáng)yRun_SimpleFile()函數(shù)可以更好地從文件中獲取Python代碼,從而避免了分配內(nèi)存空間和加載文件內(nèi)容的麻煩。

1.2. Beyond Very High Level Embedding: An overview 超越高級(jí)嵌入:概述

The high level interface gives you the ability to execute arbitrary pieces of Python code from your application, but exchanging data values is quite cumbersome to say the least. If you want that, you should use lower level calls. At the cost of having to write more C code, you can achieve almost anything.

高級(jí)接口使您能夠從應(yīng)用程序中執(zhí)行任意段Python代碼,但是至少可以說,交換數(shù)據(jù)值非常麻煩。如果需要,應(yīng)該使用較低級(jí)別的調(diào)用。以編寫更多的C代碼為代價(jià),您幾乎可以實(shí)現(xiàn)任何目標(biāo)。

It should be noted that extending Python and embedding Python is quite the same activity, despite the different intent. Most topics discussed in the previous chapters are still valid. To show this, consider what the extension code from Python to C really does:

應(yīng)該注意的是,盡管意圖不同,但擴(kuò)展Python和嵌入Python是完全相同的活動(dòng)。前幾章討論的大多數(shù)主題仍然有效。為了說明這一點(diǎn),請(qǐng)考慮一下從Python到C的擴(kuò)展代碼的實(shí)際作用:

  • Convert data values from Python to C,
    將數(shù)據(jù)值從Python轉(zhuǎn)換為C,

  • Perform a function call to a C routine using the converted values, and
    使用轉(zhuǎn)換后的值對(duì)C例程執(zhí)行函數(shù)調(diào)用,然后

  • Convert the data values from the call from C to Python.
    將調(diào)用中的數(shù)據(jù)值從C轉(zhuǎn)換為Python。

  • When embedding Python, the interface code does:
    嵌入Python時(shí),接口代碼執(zhí)行以下操作:

  • Convert data values from C to Python,
    將數(shù)據(jù)值從C轉(zhuǎn)換為Python,

  • Perform a function call to a Python interface routine using the converted values, and
    使用轉(zhuǎn)換后的值執(zhí)行對(duì)Python接口例程的函數(shù)調(diào)用,以及

  • Convert the data values from the call from Python to C.
    將調(diào)用中的數(shù)據(jù)值從Python轉(zhuǎn)換為C。

  • As you can see, the data conversion steps are simply swapped to accommodate the different direction of the cross-language transfer. The only difference is the routine that you call between both data conversions. When extending, you call a C routine, when embedding, you call a Python routine.

    如您所見,只需轉(zhuǎn)換數(shù)據(jù)轉(zhuǎn)換步驟即可適應(yīng)跨語言傳輸?shù)牟煌较颉Nㄒ坏膮^(qū)別是兩次數(shù)據(jù)轉(zhuǎn)換之間調(diào)用的例程。擴(kuò)展時(shí),您調(diào)用C例程,嵌入時(shí),您調(diào)用Python例程。

    This chapter will not discuss how to convert data from Python to C and vice versa. Also, proper use of references and dealing with errors is assumed to be understood. Since these aspects do not differ from extending the interpreter, you can refer to earlier chapters for the required information.

    1.3. Pure Embedding 純嵌入

    The first program aims to execute a function in a Python script. Like in the section about the very high level interface, the Python interpreter does not directly interact with the application (but that will change in the next section).

    第一個(gè)程序旨在在Python腳本中執(zhí)行功能。就像在有關(guān)高級(jí)界面的部分中一樣,Python解釋器不會(huì)直接與應(yīng)用程序進(jìn)行交互(但是在下一部分中會(huì)有所變化)。

    The code to run a function defined in a Python script is:

    運(yùn)行Python腳本中定義的函數(shù)的代碼為:

    #define PY_SSIZE_T_CLEAN #include <Python.h>int main(int argc, char *argv[]) {PyObject *pName, *pModule, *pFunc;PyObject *pArgs, *pValue;int i;if (argc < 3) {fprintf(stderr,"Usage: call pythonfile funcname [args]\n");return 1;}Py_Initialize();pName = PyUnicode_DecodeFSDefault(argv[1]);/* Error checking of pName left out */pModule = PyImport_Import(pName);Py_DECREF(pName);if (pModule != NULL) {pFunc = PyObject_GetAttrString(pModule, argv[2]);/* pFunc is a new reference */if (pFunc && PyCallable_Check(pFunc)) {pArgs = PyTuple_New(argc - 3);for (i = 0; i < argc - 3; ++i) {pValue = PyLong_FromLong(atoi(argv[i + 3]));if (!pValue) {Py_DECREF(pArgs);Py_DECREF(pModule);fprintf(stderr, "Cannot convert argument\n");return 1;}/* pValue reference stolen here: */PyTuple_SetItem(pArgs, i, pValue);}pValue = PyObject_CallObject(pFunc, pArgs);Py_DECREF(pArgs);if (pValue != NULL) {printf("Result of call: %ld\n", PyLong_AsLong(pValue));Py_DECREF(pValue);}else {Py_DECREF(pFunc);Py_DECREF(pModule);PyErr_Print();fprintf(stderr,"Call failed\n");return 1;}}else {if (PyErr_Occurred())PyErr_Print();fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);}Py_XDECREF(pFunc);Py_DECREF(pModule);}else {PyErr_Print();fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);return 1;}if (Py_FinalizeEx() < 0) {return 120;}return 0; }

    This code loads a Python script using argv[1], and calls the function named in argv[2]. Its integer arguments are the other values of the argv array. If you compile and link this program (let’s call the finished executable call), and use it to execute a Python script, such as:

    此代碼使用加載Python腳本argv[1],并調(diào)用中命名的函數(shù)argv[2]。它的整數(shù)參數(shù)是argv 數(shù)組的其他值。如果編譯并鏈接該程序(讓我們調(diào)用完成的可執(zhí)行調(diào)用),并使用它執(zhí)行Python腳本,例如:

    def multiply(a,b):print("Will compute", a, "times", b)c = 0for i in range(0, a):c = c + breturn c

    then the result should be:

    那么結(jié)果應(yīng)該是:

    $ call multiply multiply 3 2 Will compute 3 times 2 Result of call: 6

    Although the program is quite large for its functionality, most of the code is for data conversion between Python and C, and for error reporting. The interesting part with respect to embedding Python starts with

    盡管該程序的功能非常龐大,但大多數(shù)代碼都是用于Python和C之間的數(shù)據(jù)轉(zhuǎn)換以及錯(cuò)誤報(bào)告。關(guān)于嵌入Python的有趣部分始于

    Py_Initialize(); pName = PyUnicode_DecodeFSDefault(argv[1]); /* Error checking of pName left out */ pModule = PyImport_Import(pName);

    After initializing the interpreter, the script is loaded using PyImport_Import(). This routine needs a Python string as its argument, which is constructed using the PyUnicode_FromString() data conversion routine.

    初始化解釋器后,使用加載腳本 PyImport_Import()。該例程需要一個(gè)Python字符串作為其參數(shù),該字符串是使用PyUnicode_FromString()數(shù)據(jù)轉(zhuǎn)換例程構(gòu)造的。

    pFunc = PyObject_GetAttrString(pModule, argv[2]); /* pFunc is a new reference */if (pFunc && PyCallable_Check(pFunc)) {... } Py_XDECREF(pFunc);

    Once the script is loaded, the name we’re looking for is retrieved using PyObject_GetAttrString(). If the name exists, and the object returned is callable, you can safely assume that it is a function. The program then proceeds by constructing a tuple of arguments as normal. The call to the Python function is then made with:

    加載腳本后,將使用查找所需的名稱 PyObject_GetAttrString()。如果名稱存在,并且返回的對(duì)象是可調(diào)用的,則可以安全地假定它是一個(gè)函數(shù)。然后,程序通過正常構(gòu)造參數(shù)元組繼續(xù)進(jìn)行。然后使用以下命令調(diào)用Python函數(shù):

    pValue = PyObject_CallObject(pFunc, pArgs);

    Upon return of the function, pValue is either NULL or it contains a reference to the return value of the function. Be sure to release the reference after examining the value.

    函數(shù)返回時(shí),pValue是NULL或包含對(duì)函數(shù)返回值的引用。檢查值之后,請(qǐng)確保釋放參考。

    1.4. Extending Embedded Python

    Until now, the embedded Python interpreter had no access to functionality from the application itself. The Python API allows this by extending the embedded interpreter. That is, the embedded interpreter gets extended with routines provided by the application. While it sounds complex, it is not so bad. Simply forget for a while that the application starts the Python interpreter. Instead, consider the application to be a set of subroutines, and write some glue code that gives Python access to those routines, just like you would write a normal Python extension. For example:

    到目前為止,嵌入式Python解釋器無法從應(yīng)用程序本身訪問功能。Python API通過擴(kuò)展嵌入式解釋器來實(shí)現(xiàn)這一點(diǎn)。也就是說,嵌入式解釋器將使用應(yīng)用程序提供的例程進(jìn)行擴(kuò)展。雖然聽起來很復(fù)雜,但還不錯(cuò)。只需暫時(shí)忘記應(yīng)用程序啟動(dòng)Python解釋器。相反,應(yīng)將應(yīng)用程序視為一組子例程,并編寫一些粘合代碼以使Python可以訪問這些例程,就像編寫普通的Python擴(kuò)展一樣。例如:

    static int numargs=0;/* Return the number of arguments of the application command line */ static PyObject* emb_numargs(PyObject *self, PyObject *args) {if(!PyArg_ParseTuple(args, ":numargs"))return NULL;return PyLong_FromLong(numargs); }static PyMethodDef EmbMethods[] = {{"numargs", emb_numargs, METH_VARARGS,"Return the number of arguments received by the process."},{NULL, NULL, 0, NULL} };static PyModuleDef EmbModule = {PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,NULL, NULL, NULL, NULL };static PyObject* PyInit_emb(void) {return PyModule_Create(&EmbModule); }

    Insert the above code just above the main() function. Also, insert the following two statements before the call to Py_Initialize():

    在main()函數(shù)上方插入上面的代碼。另外,在對(duì)的調(diào)用之前插入以下兩個(gè)語句Py_Initialize():

    numargs = argc; PyImport_AppendInittab("emb", &PyInit_emb);

    These two lines initialize the numargs variable, and make the emb.numargs() function accessible to the embedded Python interpreter. With these extensions, the Python script can do things like

    這兩行初始化numargs變量,并使該 emb.numargs()函數(shù)可被嵌入式Python解釋器訪問。通過這些擴(kuò)展,Python腳本可以執(zhí)行以下操作

    import emb print("Number of arguments", emb.numargs())

    In a real application, the methods will expose an API of the application to Python.

    在實(shí)際的應(yīng)用程序中,這些方法會(huì)將應(yīng)用程序的API公開給Python。

    1.5. Embedding Python in C++ 在C ++中嵌入Python

    It is also possible to embed Python in a C++ program; precisely how this is done will depend on the details of the C++ system used; in general you will need to write the main program in C++, and use the C++ compiler to compile and link your program. There is no need to recompile Python itself using C++.

    也可以將Python嵌入C ++程序中。確切地講,這將取決于所使用的C ++系統(tǒng)的細(xì)節(jié)。通常,您將需要用C ++編寫主程序,并使用C ++編譯器來編譯和鏈接程序。無需使用C ++重新編譯Python本身。

    1.6. Compiling and Linking under Unix-like systems 編譯和在類Unix系統(tǒng)鏈接

    It is not necessarily trivial to find the right flags to pass to your compiler (and linker) in order to embed the Python interpreter into your application, particularly because Python needs to load library modules implemented as C dynamic extensions (.so files) linked against it.

    找到正確的標(biāo)志傳遞給編譯器(和鏈接器)以將Python解釋器嵌入到您的應(yīng)用程序中并不一定很簡(jiǎn)單,尤其是因?yàn)镻ython需要加載實(shí)現(xiàn)為.so與其鏈接的C動(dòng)態(tài)擴(kuò)展(文件)的庫模塊。

    To find out the required compiler and linker flags, you can execute the pythonX.Y-config script which is generated as part of the installation process (a python3-config script may also be available). This script has several options, of which the following will be directly useful to you:

    要找出所需的編譯器和鏈接器標(biāo)志,您可以執(zhí)行 在安裝過程中生成的腳本(也可以使用腳本)。該腳本有多個(gè)選項(xiàng),其中的以下選項(xiàng)對(duì)您直接有用:pythonX.Y-configpython3-config

    • pythonX.Y-config --cflags will give you the recommended flags when compiling:
      pythonX.Y-config --cflags 編譯時(shí)會(huì)給您推薦的標(biāo)志:
    $ /opt/bin/python3.4-config --cflags -I/opt/include/python3.4m -I/opt/include/python3.4m -DNDEBUG -g -fwrapv -O3 -Wall -Wstrict-prototypes
    • pythonX.Y-config --ldflags will give you the recommended flags when linking:
      pythonX.Y-config --ldflags 鏈接時(shí)會(huì)為您提供推薦的標(biāo)志:
    $ /opt/bin/python3.4-config --ldflags -L/opt/lib/python3.4/config-3.4m -lpthread -ldl -lutil -lm -lpython3.4m -Xlinker -export-dynamic

    注解 To avoid confusion between several Python installations (and especially between the system Python and your own compiled Python), it is recommended that you use the absolute path to pythonX.Y-config, as in the above example.

    注解 為了避免一些Python的設(shè)備之間的混淆(尤其是系統(tǒng)Python和自己編譯的Python之間),因此建議您使用絕對(duì)路徑,如上面的例子。pythonX.Y-config

    If this procedure doesn’t work for you (it is not guaranteed to work for all Unix-like platforms; however, we welcome bug reports) you will have to read your system’s documentation about dynamic linking and/or examine Python’s Makefile (use sysconfig.get_makefile_filename() to find its location) and compilation options. In this case, the sysconfig module is a useful tool to programmatically extract the configuration values that you will want to combine together. For example:

    如果此程序?qū)δ黄鹱饔?#xff08;不能保證在所有類Unix平臺(tái)上都有效;但是,我們歡迎提供錯(cuò)誤報(bào)告),則您必須閱讀系統(tǒng)文檔中有關(guān)動(dòng)態(tài)鏈接和/或檢查Python的文檔Makefile(用于sysconfig.get_makefile_filename() 查找其位置)和編譯選項(xiàng)。在這種情況下,該sysconfig模塊是有用的工具,可用于以編程方式提取要組合在一起的配置值。例如:

    >>> import sysconfig >>> sysconfig.get_config_var('LIBS') '-lpthread -ldl -lutil' >>> sysconfig.get_config_var('LINKFORSHARED') '-Xlinker -export-dynamic'

    參考文章:Embedding Python in Another Application

    總結(jié)

    以上是生活随笔為你收集整理的如何在C++中调用python程序?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。