文章目录

  • 1. Embedding Python in Another Application 将Python嵌入另一个应用程序中
    • 1.1. Very High Level Embedding 高层嵌入
    • 1.2. Beyond Very High Level Embedding: An overview 超越高级嵌入:概述
    • 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系统链接

1. Embedding Python in Another Application 将Python嵌入另一个应用程序中

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.

前面的章节讨论了如何扩展Python,即如何通过将C函数库附加到Python来扩展Python的功能。也可以通过其他方式做到这一点:通过将Python嵌入到C / C ++应用程序中来丰富它。嵌入为您的应用程序提供了使用Python而非C或C ++实现应用程序某些功能的能力。这可以用于许多目的。一个示例是允许用户通过使用Python编写一些脚本来根据自己的需求定制应用程序。如果某些功能可以更轻松地用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与扩展Python类似,但不完全相同。区别在于,当您扩展Python时,应用程序的主程序仍然是Python解释器,而如果您嵌入Python,则主程序可能与Python无关—相反,应用程序的某些部分有时会调用Python解释器运行一些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,那么您将提供自己的主程序。这个主程序要做的一件事就是初始化Python解释器。至少,您必须调用函数Py_Initialize()。有一些可选的调用,可将命令行参数传递给Python。然后,您可以从应用程序的任何部分调用解释器。

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.

有几种不同的调用解释器的方式:可以将包含Python语句的字符串传递给PyRun_SimpleString(),或者可以将stdio文件指针和文件名(仅用于错误消息中的标识)传递给PyRun_SimpleFile()。您还可以调用前面各章中描述的较低级别的操作来构造和使用Python对象。

参见
Python/C API 参考手册
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的最简单形式是使用非常高级的接口。该接口旨在执行Python脚本,而无需直接与应用程序进行交互。例如,这可用于对文件执行某些操作。

#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()通知解释器有关Python运行时库的路径之前,应先调用该函数 。接下来,使用初始化Python解释器 Py_Initialize(),然后执行打印日期和时间的硬编码Python脚本。之后,该Py_FinalizeEx()调用将关闭解释器,然后结束程序。在实际程序中,您可能希望从其他来源(可能是文本编辑器例程,文件或数据库)获取Python脚本。使用该PyRun_SimpleFile()函数可以更好地从文件中获取Python代码,从而避免了分配内存空间和加载文件内容的麻烦。

1.2. Beyond Very High Level Embedding: An overview 超越高级嵌入:概述

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.

高级接口使您能够从应用程序中执行任意段Python代码,但是至少可以说,交换数据值非常麻烦。如果需要,应该使用较低级别的调用。以编写更多的C代码为代价,您几乎可以实现任何目标。

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:

应该注意的是,尽管意图不同,但扩展Python和嵌入Python是完全相同的活动。前几章讨论的大多数主题仍然有效。为了说明这一点,请考虑一下从Python到C的扩展代码的实际作用:

  1. Convert data values from Python to C,
    将数据值从Python转换为C,

  2. Perform a function call to a C routine using the converted values, and
    使用转换后的值对C例程执行函数调用,然后

  3. Convert the data values from the call from C to Python.
    将调用中的数据值从C转换为Python。

When embedding Python, the interface code does:
嵌入Python时,接口代码执行以下操作:

  1. Convert data values from C to Python,
    将数据值从C转换为Python,

  2. Perform a function call to a Python interface routine using the converted values, and
    使用转换后的值执行对Python接口例程的函数调用,以及

  3. Convert the data values from the call from Python to C.
    将调用中的数据值从Python转换为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.

如您所见,只需转换数据转换步骤即可适应跨语言传输的不同方向。唯一的区别是两次数据转换之间调用的例程。扩展时,您调用C例程,嵌入时,您调用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).

第一个程序旨在在Python脚本中执行功能。就像在有关高级界面的部分中一样,Python解释器不会直接与应用程序进行交互(但是在下一部分中会有所变化)。

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

运行Python脚本中定义的函数的代码为:

#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],并调用中命名的函数argv[2]。它的整数参数是argv 数组的其他值。如果编译并链接该程序(让我们调用完成的可执行调用),并使用它执行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:

那么结果应该是:

$ 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

尽管该程序的功能非常庞大,但大多数代码都是用于Python和C之间的数据转换以及错误报告。关于嵌入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()。该例程需要一个Python字符串作为其参数,该字符串是使用PyUnicode_FromString()数据转换例程构造的。

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()。如果名称存在,并且返回的对象是可调用的,则可以安全地假定它是一个函数。然后,程序通过正常构造参数元组继续进行。然后使用以下命令调用Python函数:

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.

函数返回时,pValueNULL或包含对函数返回值的引用。检查值之后,请确保释放参考。

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解释器无法从应用程序本身访问功能。Python API通过扩展嵌入式解释器来实现这一点。也就是说,嵌入式解释器将使用应用程序提供的例程进行扩展。虽然听起来很复杂,但还不错。只需暂时忘记应用程序启动Python解释器。相反,应将应用程序视为一组子例程,并编写一些粘合代码以使Python可以访问这些例程,就像编写普通的Python扩展一样。例如:

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()函数上方插入上面的代码。另外,在对的调用之前插入以下两个语句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()函数可被嵌入式Python解释器访问。通过这些扩展,Python脚本可以执行以下操作

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

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

在实际的应用程序中,这些方法会将应用程序的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 ++系统的细节。通常,您将需要用C ++编写主程序,并使用C ++编译器来编译和链接程序。无需使用C ++重新编译Python本身。

1.6. Compiling and Linking under Unix-like systems 编译和在类Unix系统链接

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.

找到正确的标志传递给编译器(和链接器)以将Python解释器嵌入到您的应用程序中并不一定很简单,尤其是因为Python需要加载实现为.so与其链接的C动态扩展(文件)的库模块。

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:

要找出所需的编译器和链接器标志,您可以执行 在安装过程中生成的脚本(也可以使用脚本)。该脚本有多个选项,其中的以下选项对您直接有用:pythonX.Y-configpython3-config

  • pythonX.Y-config --cflags will give you the recommended flags when compiling:
    pythonX.Y-config --cflags 编译时会给您推荐的标志:
$ /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 链接时会为您提供推荐的标志:
$ /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的设备之间的混淆(尤其是系统Python和自己编译的Python之间),因此建议您使用绝对路径,如上面的例子。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:

如果此程序对您不起作用(不能保证在所有类Unix平台上都有效;但是,我们欢迎提供错误报告),则您必须阅读系统文档中有关动态链接和/或检查Python的文档Makefile(用于sysconfig.get_makefile_filename() 查找其位置)和编译选项。在这种情况下,该sysconfig模块是有用的工具,可用于以编程方式提取要组合在一起的配置值。例如:

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

参考文章:Embedding Python in Another Application

如何在C++中调用python程序?相关推荐

  1. m 文件 dll matlab 中调用_如何在matlab中调用python程序

    现在python很火,很多代码都是python写的,如果你和我一样,习惯了使用matlab,还想在matlab中调用Python的代码,应该怎么办呢?其中一条思路:首先在matlab中调用系统脚本命令 ...

  2. php调用python绘图程序_如何在matlab中调用python程序

    现在python很火,很多代码都是python写的,如果你和我一样,习惯了使用matlab,还想在matlab中调用Python的代码,应该怎么办呢?其中一条思路:首先在matlab中调用系统脚本命令 ...

  3. 如何在HTML文档中调用Python程序?

    如何在HTML文档中调用Python程序? 简介: ​ 前几天突然遇到这样的一个需求,在html页面中调用python程序对图像进行处理,之后将处理后的图像重新显示在页面中.刚开始还不知道html页面 ...

  4. fortran语言和python_如何在Fortran中调用Python

    Python是机器学习领域不断增长的通用语言.拥有一些非常棒的工具包,比如scikit-learn,tensorflow和pytorch.气候模式通常是使用Fortran实现的.那么我们应该将基于Py ...

  5. excel调用python编程-如何在excel中调用python脚本

    如何在excel中调用python脚本 发布时间:2020-07-03 14:15:28 来源:亿速云 阅读:155 如何在excel中调用python脚本?针对这个问题,这篇文章详细介绍了相对应的分 ...

  6. 【Python】如何在Excel中调用Python脚本,实现数据自动化处理

    这次我们会介绍如何使用xlwings将Python和Excel两大数据工具进行集成,更便捷地处理日常工作. 说起Excel,那绝对是数据处理领域王者般的存在,尽管已经诞生三十多年了,现在全球仍有7.5 ...

  7. java能调用python吗_如何使用运行时在Java中调用python程序 - java

    我想用来自Java的参数调用python程序.但是我的输出是空白.代码在这里. Python代码在这里: import sys print(sys.argv[1]) Java代码在这里: public ...

  8. java怎么调用python_如何在Java中调用Python代码

    Jython(原JPython),是一个用2113Java语言写的Python解释5261器.在没有第三方模块的情况下4102,通常选择利用Jython来调用1653Python代码,它是一个开源的J ...

  9. 如何在Excel中调用Python脚本,实现数据自动化处理!

    大家好, 这次我们会介绍如何使用xlwings将Python和Excel两大数据工具进行集成,更便捷地处理日常工作. 说起Excel,那绝对是数据处理领域王者般的存在,尽管已经诞生三十多年了,现在全球 ...

最新文章

  1. python学习笔记(装饰器、迭代器生成器、内置函数、软件目录开发规范)
  2. Shell之while循环
  3. 个人图书管理系统c语言代码,c语言源代码---------------个人图书管理系统
  4. JavaScript——易班优课YOOC课群在线测试禁止查卷解决方案
  5. 【数据库系统概论】考研重点章节分析【0】
  6. python 杀死子进程_Python:当父异常终止时,如何杀死子进程?
  7. java 调用祖父方法_在Java中调用祖父母方法:您不能
  8. python 打印文件名_在Python中打印文件名,关闭状态和文件模式
  9. ubuntu创建可执行图标、设置文件默认打开方式
  10. 电脑自建服务器tomcat,怎么配置搭建tomcat服务器
  11. ai面试的优缺点_AI面试是什么?有哪些特点呢?
  12. Zoommy for mac(图片素材搜索下载软件)
  13. twm配置文件.twmrc
  14. Linux用户获得超级管理员权限
  15. 毕业设计:电子/通信/物联网/计算机专业选题目参考(嵌入式linux/单片机STM32/web/图像)
  16. 计算机主机突然断电有什么影响吗,断电对电脑硬件会产生哪些影响
  17. 网站建设用国内域名好还是国外域名好?
  18. 游戏‘微信打飞机’ 第三课
  19. 无人机动力系统扭矩测量方法和测试必要性的研究
  20. Java_发展史简介

热门文章

  1. 【ABAP】更新交货单交货数量和拣配数量
  2. 360浏览器的收藏栏不见了怎么办?
  3. SAP为企业不同员工带来了什么?
  4. WSAENOBUFS: No buffer space available in SAP
  5. ABAP选择屏幕建议
  6. 选择头秃还是植发?大数据告诉你植发行业水有多深?
  7. 50%人使用视听设备音量超标,如何正确佩戴耳机?
  8. 爱优腾芒“跑马圈地”,AI广告营销能拯救“盈利难”的视频平台吗?
  9. 产业互联网时代,猪是如何上天的
  10. java线程概念_《Java基础知识》Java线程的概念