企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
### 导航 - [索引](../genindex.xhtml "总目录") - [模块](../py-modindex.xhtml "Python 模块索引") | - [下一页](windows.xhtml "Python在Windows上的常见问题") | - [上一页](library.xhtml "代码库和插件 FAQ") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) » - zh\_CN 3.7.3 [文档](../index.xhtml) » - [Python 常见问题](index.xhtml) » - $('.inline-search').show(0); | # [扩展/嵌入常见问题](#id3) 目录 - [扩展/嵌入常见问题](#extending-embedding-faq) - [可以使用C语言中创建自己的函数吗?](#can-i-create-my-own-functions-in-c) - [可以使用C++语言中创建自己的函数吗?](#id2) - [C很难写,有没有其他选择?](#writing-c-is-hard-are-there-any-alternatives) - [如何从C执行任意Python语句?](#how-can-i-execute-arbitrary-python-statements-from-c) - [如何从C中评估任意Python表达式?](#how-can-i-evaluate-an-arbitrary-python-expression-from-c) - [如何从Python对象中提取C的值?](#how-do-i-extract-c-values-from-a-python-object) - [如何使用Py\_BuildValue()创建任意长度的元组?](#how-do-i-use-py-buildvalue-to-create-a-tuple-of-arbitrary-length) - [如何从C调用对象的方法?](#how-do-i-call-an-object-s-method-from-c) - [如何捕获PyErr\_Print()(或打印到stdout / stderr的任何内容)的输出?](#how-do-i-catch-the-output-from-pyerr-print-or-anything-that-prints-to-stdout-stderr) - [如何从C访问用Python编写的模块?](#how-do-i-access-a-module-written-in-python-from-c) - [如何从Python接口到C ++对象?](#how-do-i-interface-to-c-objects-from-python) - [我使用Setup文件添加了一个模块,为什么make失败了?](#i-added-a-module-using-the-setup-file-and-the-make-fails-why) - [如何调试扩展?](#how-do-i-debug-an-extension) - [我想在Linux系统上编译一个Python模块,但是缺少一些文件。为什么?](#i-want-to-compile-a-python-module-on-my-linux-system-but-some-files-are-missing-why) - [如何区分“输入不完整”和“输入无效”?](#how-do-i-tell-incomplete-input-from-invalid-input) - [如何找到未定义的g++符号\_\_builtin\_new或\_\_pure\_virtual?](#how-do-i-find-undefined-g-symbols-builtin-new-or-pure-virtual) - [能否创建一个对象类,其中部分方法在C中实现,而其他方法在Python中实现(例如通过继承)?](#can-i-create-an-object-class-with-some-methods-implemented-in-c-and-others-in-python-e-g-through-inheritance) ## [可以使用C语言中创建自己的函数吗?](#id4) 是的,您可以在C中创建包含函数、变量、异常甚至新类型的内置模块。在文档 [扩展和嵌入 Python 解释器](../extending/index.xhtml#extending-index) 中有说明。 大多数中级或高级的Python书籍也涵盖这个主题。 ## [可以使用C++语言中创建自己的函数吗?](#id5) 是的,可以使用C ++中兼容C的功能。 在Python include文件周围放置` extern“C”{...}` ,并在Python解释器调用的每个函数之前放置 `extern“C”` 。 具有构造函数的全局或静态C ++对象可能不是一个好主意。 ## [C很难写,有没有其他选择?](#id6) 编写自己的C扩展有很多选择,具体取决于您要做的事情。 [Cython](http://cython.org) \[http://cython.org\] 及其相关的 [Pyrex](https://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/) \[https://www.cosc.canterbury.ac.nz/greg.ewing/python/Pyrex/\] 是接受稍微修改过的Python形式并生成相应C代码的编译器。 Cython和Pyrex可以编写扩展而无需学习Python的C API。 如果需要连接到某些当前不存在Python扩展的C或C ++库,可以尝试使用 [SWIG](http://www.swig.org) \[http://www.swig.org\] 等工具包装库的数据类型和函数。 [SIP](https://riverbankcomputing.com/software/sip/intro) \[https://riverbankcomputing.com/software/sip/intro\] , [CXX](http://cxx.sourceforge.net/) \[http://cxx.sourceforge.net/\] [Boost](http://www.boost.org/libs/python/doc/index.html) \[http://www.boost.org/libs/python/doc/index.html\] , 或 [Weave](https://github.com/scipy/weave) \[https://github.com/scipy/weave\] 也是包装C ++库的替代方案。 ## [如何从C执行任意Python语句?](#id7) The highest-level function to do this is [`PyRun_SimpleString()`](../c-api/veryhigh.xhtml#c.PyRun_SimpleString "PyRun_SimpleString") which takes a single string argument to be executed in the context of the module `__main__` and returns `0` for success and `-1` when an exception occurred (including [`SyntaxError`](../library/exceptions.xhtml#SyntaxError "SyntaxError")). If you want more control, use [`PyRun_String()`](../c-api/veryhigh.xhtml#c.PyRun_String "PyRun_String"); see the source for [`PyRun_SimpleString()`](../c-api/veryhigh.xhtml#c.PyRun_SimpleString "PyRun_SimpleString") in `Python/pythonrun.c`. ## [如何从C中评估任意Python表达式?](#id8) Call the function [`PyRun_String()`](../c-api/veryhigh.xhtml#c.PyRun_String "PyRun_String") from the previous question with the start symbol [`Py_eval_input`](../c-api/veryhigh.xhtml#c.Py_eval_input "Py_eval_input"); it parses an expression, evaluates it and returns its value. ## [如何从Python对象中提取C的值?](#id9) That depends on the object's type. If it's a tuple, [`PyTuple_Size()`](../c-api/tuple.xhtml#c.PyTuple_Size "PyTuple_Size")returns its length and [`PyTuple_GetItem()`](../c-api/tuple.xhtml#c.PyTuple_GetItem "PyTuple_GetItem") returns the item at a specified index. Lists have similar functions, `PyListSize()` and [`PyList_GetItem()`](../c-api/list.xhtml#c.PyList_GetItem "PyList_GetItem"). For bytes, [`PyBytes_Size()`](../c-api/bytes.xhtml#c.PyBytes_Size "PyBytes_Size") returns its length and [`PyBytes_AsStringAndSize()`](../c-api/bytes.xhtml#c.PyBytes_AsStringAndSize "PyBytes_AsStringAndSize") provides a pointer to its value and its length. Note that Python bytes objects may contain null bytes so C's `strlen()` should not be used. 要测试对象的类型,首先要确保它不是 *NULL* ,然后使用 [`PyBytes_Check()`](../c-api/bytes.xhtml#c.PyBytes_Check "PyBytes_Check") , [`PyTuple_Check()`](../c-api/tuple.xhtml#c.PyTuple_Check "PyTuple_Check") , [`PyList_Check()`](../c-api/list.xhtml#c.PyList_Check "PyList_Check") 等 There is also a high-level API to Python objects which is provided by the so-called 'abstract' interface -- read `Include/abstract.h` for further details. It allows interfacing with any kind of Python sequence using calls like [`PySequence_Length()`](../c-api/sequence.xhtml#c.PySequence_Length "PySequence_Length"), [`PySequence_GetItem()`](../c-api/sequence.xhtml#c.PySequence_GetItem "PySequence_GetItem"), etc. as well as many other useful protocols such as numbers ([`PyNumber_Index()`](../c-api/number.xhtml#c.PyNumber_Index "PyNumber_Index") et al.) and mappings in the PyMapping APIs. ## [如何使用Py\_BuildValue()创建任意长度的元组?](#id10) 不可以。应该使用 [`PyTuple_Pack()`](../c-api/tuple.xhtml#c.PyTuple_Pack "PyTuple_Pack") 。 ## [如何从C调用对象的方法?](#id11) The [`PyObject_CallMethod()`](../c-api/object.xhtml#c.PyObject_CallMethod "PyObject_CallMethod") function can be used to call an arbitrary method of an object. The parameters are the object, the name of the method to call, a format string like that used with [`Py_BuildValue()`](../c-api/arg.xhtml#c.Py_BuildValue "Py_BuildValue"), and the argument values: ``` PyObject * PyObject_CallMethod(PyObject *object, const char *method_name, const char *arg_format, ...); ``` This works for any object that has methods -- whether built-in or user-defined. You are responsible for eventually [`Py_DECREF()`](../c-api/refcounting.xhtml#c.Py_DECREF "Py_DECREF")'ing the return value. To call, e.g., a file object's "seek" method with arguments 10, 0 (assuming the file object pointer is "f"): ``` res = PyObject_CallMethod(f, "seek", "(ii)", 10, 0); if (res == NULL) { ... an exception occurred ... } else { Py_DECREF(res); } ``` Note that since [`PyObject_CallObject()`](../c-api/object.xhtml#c.PyObject_CallObject "PyObject_CallObject") *always* wants a tuple for the argument list, to call a function without arguments, pass "()" for the format, and to call a function with one argument, surround the argument in parentheses, e.g. "(i)". ## [如何捕获PyErr\_Print()(或打印到stdout / stderr的任何内容)的输出?](#id12) In Python code, define an object that supports the `write()` method. Assign this object to [`sys.stdout`](../library/sys.xhtml#sys.stdout "sys.stdout") and [`sys.stderr`](../library/sys.xhtml#sys.stderr "sys.stderr"). Call print\_error, or just allow the standard traceback mechanism to work. Then, the output will go wherever your `write()` method sends it. The easiest way to do this is to use the [`io.StringIO`](../library/io.xhtml#io.StringIO "io.StringIO") class: ``` >>> import io, sys >>> sys.stdout = io.StringIO() >>> print('foo') >>> print('hello world!') >>> sys.stderr.write(sys.stdout.getvalue()) foo hello world! ``` A custom object to do the same would look like this: ``` >>> import io, sys >>> class StdoutCatcher(io.TextIOBase): ... def __init__(self): ... self.data = [] ... def write(self, stuff): ... self.data.append(stuff) ... >>> import sys >>> sys.stdout = StdoutCatcher() >>> print('foo') >>> print('hello world!') >>> sys.stderr.write(''.join(sys.stdout.data)) foo hello world! ``` ## [如何从C访问用Python编写的模块?](#id13) You can get a pointer to the module object as follows: ``` module = PyImport_ImportModule("<modulename>"); ``` If the module hasn't been imported yet (i.e. it is not yet present in [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules")), this initializes the module; otherwise it simply returns the value of `sys.modules["<modulename>"]`. Note that it doesn't enter the module into any namespace -- it only ensures it has been initialized and is stored in [`sys.modules`](../library/sys.xhtml#sys.modules "sys.modules"). You can then access the module's attributes (i.e. any name defined in the module) as follows: ``` attr = PyObject_GetAttrString(module, "<attrname>"); ``` Calling [`PyObject_SetAttrString()`](../c-api/object.xhtml#c.PyObject_SetAttrString "PyObject_SetAttrString") to assign to variables in the module also works. ## [如何从Python接口到C ++对象?](#id14) Depending on your requirements, there are many approaches. To do this manually, begin by reading [the "Extending and Embedding" document](../extending/index.xhtml#extending-index). Realize that for the Python run-time system, there isn't a whole lot of difference between C and C++ -- so the strategy of building a new Python type around a C structure (pointer) type will also work for C++ objects. 有关C ++库,请参阅 [C很难写,有没有其他选择?](#c-wrapper-software) ## [我使用Setup文件添加了一个模块,为什么make失败了?](#id15) 安装程序必须以换行符结束,如果没有换行符,则构建过程将失败。 (修复这个需要一些丑陋的shell脚本编程,而且这个bug很小,看起来不值得花这么大力气。) ## [如何调试扩展?](#id16) 将GDB与动态加载的扩展名一起使用时,在加载扩展名之前,不能在扩展名中设置断点。 在您的 `.gdbinit` 文件中(或交互式)添加命令: ``` br _PyImport_LoadDynamicModule ``` 然后运行GDB: ``` $ gdb /local/bin/python gdb) run myscript.py gdb) continue # repeat until your extension is loaded gdb) finish # so that your extension is loaded gdb) br myfunction.c:50 gdb) continue ``` ## [我想在Linux系统上编译一个Python模块,但是缺少一些文件。为什么?](#id17) 大多数打包的Python版本不包含 `/usr/lib/python2.x/config/` 目录,该目录中包含编译Python扩展所需的各种文件。 对于Red Hat,安装python-devel RPM以获取必要的文件。 对于Debian,运行 `apt-get install python-dev` 。 ## [如何区分“输入不完整”和“输入无效”?](#id18) 有时,希望模仿Python交互式解释器的行为,在输入不完整时(例如,您键入了“if”语句的开头,或者没有关闭括号或三个字符串引号),给出一个延续提示,但当输入无效时,立即给出一条语法错误消息。 在Python中,您可以使用 [`codeop`](../library/codeop.xhtml#module-codeop "codeop: Compile (possibly incomplete) Python code.") 模块,该模块非常接近解析器的行为。例如,IDLE就使用了这个。 在C中执行此操作的最简单方法是调用 [`PyRun_InteractiveLoop()`](../c-api/veryhigh.xhtml#c.PyRun_InteractiveLoop "PyRun_InteractiveLoop") (可能在单独的线程中)并让Python解释器为您处理输入。您还可以设置 [`PyOS_ReadlineFunctionPointer()`](../c-api/veryhigh.xhtml#c.PyOS_ReadlineFunctionPointer "PyOS_ReadlineFunctionPointer") 指向您的自定义输入函数。有关更多提示,请参阅 `Modules/readline.c` 和 `Parser/myreadline.c` 。 但是,有时必须在与其他应用程序相同的线程中运行嵌入式Python解释器,并且不能允许 [`PyRun_InteractiveLoop()`](../c-api/veryhigh.xhtml#c.PyRun_InteractiveLoop "PyRun_InteractiveLoop") 在等待用户输入时停止。那么另一个解决方案是调用 `PyParser_ParseString()` 并测试 `e.error` 等于 `E_EOF` ,如果等于,就意味着输入不完整。这是一个示例代码片段,未经测试,灵感来自Alex Farber的代码: ``` #define PY_SSIZE_T_CLEAN #include <Python.h> #include <node.h> #include <errcode.h> #include <grammar.h> #include <parsetok.h> #include <compile.h> int testcomplete(char *code) /* code should end in \n */ /* return -1 for error, 0 for incomplete, 1 for complete */ { node *n; perrdetail e; n = PyParser_ParseString(code, &_PyParser_Grammar, Py_file_input, &e); if (n == NULL) { if (e.error == E_EOF) return 0; return -1; } PyNode_Free(n); return 1; } ``` 另一个解决方案是尝试使用 [`Py_CompileString()`](../c-api/veryhigh.xhtml#c.Py_CompileString "Py_CompileString") 编译接收到的字符串。如果编译时没有出现错误,请尝试通过调用 [`PyEval_EvalCode()`](../c-api/veryhigh.xhtml#c.PyEval_EvalCode "PyEval_EvalCode") 来执行返回的代码对象。否则,请将输入保存到以后。如果编译失败,找出是错误还是只需要更多的输入-从异常元组中提取消息字符串,并将其与字符串 “分析时意外的EOF” 进行比较。下面是使用GNUreadline库的完整示例(您可能希望在调用readline()时忽略 **SIGINT** ): ``` #include <stdio.h> #include <readline.h> #define PY_SSIZE_T_CLEAN #include <Python.h> #include <object.h> #include <compile.h> #include <eval.h> int main (int argc, char* argv[]) { int i, j, done = 0; /* lengths of line, code */ char ps1[] = ">>> "; char ps2[] = "... "; char *prompt = ps1; char *msg, *line, *code = NULL; PyObject *src, *glb, *loc; PyObject *exc, *val, *trb, *obj, *dum; Py_Initialize (); loc = PyDict_New (); glb = PyDict_New (); PyDict_SetItemString (glb, "__builtins__", PyEval_GetBuiltins ()); while (!done) { line = readline (prompt); if (NULL == line) /* Ctrl-D pressed */ { done = 1; } else { i = strlen (line); if (i > 0) add_history (line); /* save non-empty lines */ if (NULL == code) /* nothing in code yet */ j = 0; else j = strlen (code); code = realloc (code, i + j + 2); if (NULL == code) /* out of memory */ exit (1); if (0 == j) /* code was empty, so */ code[0] = '\0'; /* keep strncat happy */ strncat (code, line, i); /* append line to code */ code[i + j] = '\n'; /* append '\n' to code */ code[i + j + 1] = '\0'; src = Py_CompileString (code, "<stdin>", Py_single_input); if (NULL != src) /* compiled just fine - */ { if (ps1 == prompt || /* ">>> " or */ '\n' == code[i + j - 1]) /* "... " and double '\n' */ { /* so execute it */ dum = PyEval_EvalCode (src, glb, loc); Py_XDECREF (dum); Py_XDECREF (src); free (code); code = NULL; if (PyErr_Occurred ()) PyErr_Print (); prompt = ps1; } } /* syntax error or E_EOF? */ else if (PyErr_ExceptionMatches (PyExc_SyntaxError)) { PyErr_Fetch (&exc, &val, &trb); /* clears exception! */ if (PyArg_ParseTuple (val, "sO", &msg, &obj) && !strcmp (msg, "unexpected EOF while parsing")) /* E_EOF */ { Py_XDECREF (exc); Py_XDECREF (val); Py_XDECREF (trb); prompt = ps2; } else /* some other syntax error */ { PyErr_Restore (exc, val, trb); PyErr_Print (); free (code); code = NULL; prompt = ps1; } } else /* some non-syntax error */ { PyErr_Print (); free (code); code = NULL; prompt = ps1; } free (line); } } Py_XDECREF(glb); Py_XDECREF(loc); Py_Finalize(); exit(0); } ``` ## [如何找到未定义的g++符号\_\_builtin\_new或\_\_pure\_virtual?](#id19) 要动态加载g ++扩展模块,必须重新编译Python,要使用g ++重新链接(在Python Modules Makefile中更改LINKCC),及链接扩展模块(例如: `g++ -shared -o mymodule.so mymodule.o` )。 ## [能否创建一个对象类,其中部分方法在C中实现,而其他方法在Python中实现(例如通过继承)?](#id20) 是的,您可以继承内置类,例如 [`int`](../library/functions.xhtml#int "int") , [`list`](../library/stdtypes.xhtml#list "list") , [`dict`](../library/stdtypes.xhtml#dict "dict") 等。 Boost Python库(BPL,http://www.boost.org/libs/python/doc/index.html)提供了一种从C ++执行此操作的方法(即,您可以使用BPL继承自C ++编写的扩展类 )。 ### 导航 - [索引](../genindex.xhtml "总目录") - [模块](../py-modindex.xhtml "Python 模块索引") | - [下一页](windows.xhtml "Python在Windows上的常见问题") | - [上一页](library.xhtml "代码库和插件 FAQ") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) » - zh\_CN 3.7.3 [文档](../index.xhtml) » - [Python 常见问题](index.xhtml) » - $('.inline-search').show(0); | © [版权所有](../copyright.xhtml) 2001-2019, Python Software Foundation. Python 软件基金会是一个非盈利组织。 [请捐助。](https://www.python.org/psf/donations/) 最后更新于 5月 21, 2019. [发现了问题](../bugs.xhtml)? 使用[Sphinx](http://sphinx.pocoo.org/)1.8.4 创建。