在原书中,作者使用vs2003运行python2.5的项目,而现在配置这样的环境比较复杂,所以我尽量在配置环境上时间相差小一点,刚配置好,编译成功源文件,希望按照书上说的,修改int_print()函数,结果变化有点大,弄了很久才成功。
运行环境:
window10
vs2010
python2.7.13,编译的是PC目录里面的VS9.0的项目
先看看原书的写法:
而在python2.7中,这段代码变成了:
/* ARGSUSED */
static int
int_print(PyIntObject *v, FILE *fp, int flags)
/* flags -- not used but required by interface */
{
long int_val = v->ob_ival; // *
Py_BEGIN_ALLOW_THREADS // *
fprintf(fp, "%ld", int_val);
Py_END_ALLOW_THREADS // *
return 0;
}
加*号注释的就是原书版本中没有的,这新添加的代码导致了很大的问题,下面的图片是没有改代码之前的运行结果:
一开始,我直接把代码加到中间位置:
/* ARGSUSED */
static int
int_print(PyIntObject *v, FILE *fp, int flags)
/* flags -- not used but required by interface */
{
long int_val = v->ob_ival;
Py_BEGIN_ALLOW_THREADS
// ----------------------------------
PyObject *myStr;
myStr = PyString_FromString("I am int_print");
PyObject_Print(myStr, stdout, 0);
printf("\n");
// ----------------------------------
fprintf(fp, "%ld", int_val);
Py_END_ALLOW_THREADS
return 0;
}
结果重新生成项目报错了
我以为是PyObject在这个版本里面换了名字,后来发现没有更换,然后在网上查了很久,发现有人说,应该在函数开头定义变量,于是我这样改:
/* ARGSUSED */
static int
int_print(PyIntObject *v, FILE *fp, int flags)
/* flags -- not used but required by interface */
{
long int_val = v->ob_ival;
PyObject *myStr = NULL; // 变量定义放到开头
Py_BEGIN_ALLOW_THREADS
// ----------------------------------
myStr = PyString_FromString("I am int_print");
PyObject_Print(myStr, stdout, 0);
printf("\n");
// ----------------------------------
fprintf(fp, "%ld", int_val);
Py_END_ALLOW_THREADS
return 0;
}
然后成功编译了,
就在我以为成功了的时候,执行生成的python文件,运行一开始的代码,发现报错了,
发生了一个关于PyEval_SaveThread的错误还和NULL有关,我以为是myStr变量不能赋值为NULL,去掉以后依然报错,重新研究发现PyEval_SaveThread这个应该和线程有关,但是这部分代码里面为什么会有线程出现呢?原来是Py_BEGIN_ALLOW_THREADS和Py_END_ALLOW_THREADS,这两行代码维护了一个线程,导致myStr在里面赋值,但是在外面定义,就会报错。
知道了这个原因,我就明白代码块应该放在线程代码的前面了
/* ARGSUSED */
static int
int_print(PyIntObject *v, FILE *fp, int flags)
/* flags -- not used but required by interface */
{
long int_val = v->ob_ival;
PyObject *myStr = NULL;
// ----------------------------------
myStr = PyString_FromString("I am int_print");
PyObject_Print(myStr, stdout, 0);
printf("\n");
// ----------------------------------
Py_BEGIN_ALLOW_THREADS
fprintf(fp, "%ld", int_val);
Py_END_ALLOW_THREADS
return 0;
}
最后重新生成项目,运行python,结果输出成功!
总结:
通过今天的尝试,涡明白了在这个版本的python源代码中,变量要在开头先定义好;以及注意线程的问题。
PS.
如果编译项目的发现出现下面的错误:
那么说明你之前的Python打开以后忘记关掉了。
本人是C语言小白,没怎么接触过C语言,现在在研究Python源码,如果有什么错误,欢迎各位大佬指正,感谢!