C++回调Python的技术手段
上一篇文章《C++和Python混合编程的利器》中着重介绍了如何利用Boost Python库来实现C++和Python交互过程中的参数传递。本文将深入到Python源码并结合Python的运行机制,来分析C++回调Python的基本原理。如果对实现原理不感兴趣的同学,可以直接跳至下文中“Boost Python实现C++同步/异步回调Python的Demo” 章节,通过Demo来学习如何实现C++回调Python的方法。
Python解释器运行原理
我们都知道,使用C/C++之类的编译性语言编写的程序,是需要从源文件转换成计算机使用的机器语言,经过链接器链接之后形成了二进制的可执行文件。运行该程序的时候,就可以把二进制程序从硬盘载入到内存中运行。但是对于Python而言,Python源码不需要编译成二进制代码,它可以直接从源代码运行程序。当运行Python程序的时候,Python解释器将源代码转换为字节码,然后再由Python解释器来一条一条执行字节码指令,从而完成程序的执行。
Python编译器和字节码文件
字节码是Python编译器编译 (.py文件)生成的,生成后字节码文件格式为:.pyc,它在Python解释器中对应的是PyCodeObject对象。Python源码中对此对象定义如下:
1. /* Bytecode object */
2. typedef struct {
3. PyObject_HEAD
4. int co_argcount; /* #arguments, except *args */
5. int co_kwonlyargcount; /* #keyword only arguments */
6. int co_nlocals; /* #local variables */
7. int co_stacksize; /* #entries needed for evaluation stack */
8. int co_flags; /* CO_..., see below */
9. PyObject *co_code; /* instruction opcodes */
10. PyObject *co_consts; /* list (constants used) */
11. PyObject *co_names; /* list of strings (names used) */
12. PyObject *co_varnames; /* tuple of strings (local variable names) */
13. PyObject *co_freevars; /* tuple of strings (free variable names) */
14. PyObject *co_cellvars; /* tuple of strings (cell variable names) */
15. unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
16. PyObject *co_filename; /* unicode (where it was loaded from) */
17. PyObject *co_name; /* unicode (name, for reference) */
18. int co_firstlineno; /* first source line number */
19. PyObject *co_lnotab; /* string (encoding addrlineno mapping) See
20. Objects/lnotab_notes.txt for details. */
21. void *co_zombieframe; /* for optimization only (see frameobject.c) */
22. PyObject *co_weakreflist; /* to support weakrefs to code objects */
23. } PyCodeObject;
要了解PyCodeObject的作用,首先必须要清楚PyCodeObject结构体定义中的每一个域都表示什么含义,表1列出了PyCodeObject对象中各个域的具体意义。
字段
类型
说明
PyObject_HEAD
PyObject
PyObject_HEAD宏 定义了每个 PyObject 的初始段
co_argcount
int
代码块的位置参数的个数
co_kwonlyargcount
int
代码块的关键参数的个数
co_nlocals
int
代码块中局部变量的个数
co_stacksize
int
执行该代码块需要的栈空间
co_flags
int
co_code
PyObject *
代码块编译后的字节码指令序列,PyStringObject的形式存在
co_consts
PyObject *
代码块中所有的常量
co_names
PyObject *
代码块中所有的符号
co_varnames
PyObject *
代码块中所有的局部变量名
co_freevars
PyObject *
实现闭包使用的变量
co_cellvars
PyObject *
代码块中嵌套函数所引用的所有变量名
co_cell2arg
char *
映射单元的参数
co_filename
PyObject *
代码块对应py文件的完整路径
co_name
PyObject *
代码块的名字,通常是函数名或类名
co_firstl