49

扩展和嵌入 Python 之重定向输出与编译

 4 years ago
source link: https://mp.weixin.qq.com/s?__biz=MzUxMTk4MzY3MA%3D%3D&%3Bmid=2247483742&%3Bidx=1&%3Bsn=36a62b9ca43f9182f6e1037e994d54a8&%3Bchksm=f96a2807ce1da111eff94c4ecdb50343b8f40036b79634461cc6b56fa4cf336459b26e3
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在小长假的前一天要总结下最近的收获。

Ok,按照之前两篇嵌入和扩展 python 的文章来操作的话,现在已经可以定义自己的模块、在运行时获取异常信息。那么问题来了,在编写程序的过程中,难免有语法错误,如何在运行程序前检查这些错误呢?在编写大量 python 程序时,可以使用 IDE 辅助检查,也可以使用静态语法检查工具。如果我们自己做 python 编辑器,肯定要有语法检查的,总不能在运行时一直报语法错误,那会让人崩溃的。。。还有今天要分享的另一个话题,如何在嵌入的解释器中重新定向 print() 输出,这个在操作上也是比较简单。有了这两个骚操作,基础的功能就基本完成了。别高兴太早,之后还有更头疼的事情呢,比如, python 解释器被嵌入到了一个线程里面,然后你要中断此时线程里面的操作。。。

重定向的功能实现起来比较方便,先贴这部分程序:

static PyObject *

aview_write(PyObject *self, PyObject *args)

{

(void)self;

char *what;

if (!PyArg_ParseTuple(args, "s", &what))

{

return NULL;

}

//    QString str(what);

printf("--%s", what);

return Py_BuildValue("");

}

static PyObject*

aview_flush(PyObject* self, PyObject* args)

{

(void)self;

(void)args;

// no-op

return Py_BuildValue("");

}

static PyMethodDef MathMethods[] = {

{"add", add, METH_VARARGS,"add."},

{"write", aview_write, METH_VARARGS,"aview_write."},

{"flush", aview_flush, METH_VARARGS,"aview_flush."},

{NULL, NULL, 0, NULL}

};

static PyModuleDef MathModule = {

PyModuleDef_HEAD_INIT, "dahe", NULL, -1, MathMethods,

NULL, NULL, NULL, NULL

};

static PyObject*

PyInit_math(void)

{

PyObject* m = PyModule_Create(&MathModule);

PySys_SetObject("stdout", m);

PySys_SetObject("stderr", m);

return m;

}

相比之前的程序,又添加了write和 flush 的函数,只添加 write 函数会有警告。还有就是在初始化模块时有一些改动,将系统的标准输出与标准错误输出做了重定向。运行之前的程序结果如图:

FNJ7ZjY.png!web

这样我们静态检查的报错信息也就可以获得了。接下来介绍编译的方法。

Python的 py_compile 模块提供了一种将源文件生成字节代码的方法,我们正是利用它的编译功能去完成我们的静态语法检查。

#define COMPILEFILEPATH  "os.chdir('/root/Python/Article/redirect/pythonSource/')"

#define PYTHONPYCFILE "/root/Python/Article/redirect/compileDirectory/"

void Widget::on_pbn_compilePython_clicked()

{

qDebug() << "compile python !";

PyImport_AppendInittab("dahe", &PyInit_math);

Py_Initialize();

if (!Py_IsInitialized())

{

qDebug() << "inital faild!";

}

PyRun_SimpleString("import os");

PyRun_SimpleString(COMPILEFILEPATH);

PyRun_SimpleString("import dahe");

PyRun_SimpleString("import py_compile");

QString execFileName = "dhTest";

QString pycFilePath = QString("py_compile.compile('%1.py','%2%1.pyc')").arg(execFileName).arg(PYTHONPYCFILE);

char*  ch;

QByteArray ba = pycFilePath.toLatin1();

ch=ba.data();

PyRun_SimpleString(ch);

Py_Finalize();

}

上方是两个路径的宏,之前源代码一直存放在可执行程序的目录下,那也是默认的python工作目录,现在我们改变了工作目录。由于编译会生成字节代码文件,我们也为这些文件指定了路径。整个编译的代码是一个按钮的槽函数。我们写入错误的字符,运行编译的功能,观察效果。

UI图示:

YN7JBzE.png!web

Python源文件:

aQNbUr6.jpg!web

点击编译按钮运行结果:

YJNBJz7.jpg!web

点击运行按钮,此时是动态检查结果:

veMVJ3V.jpg!web

这样我们就实现了在运行前检查语法错误的效果了。

程序还有很多不完善的地方,希望大家不吝赐教。多谢。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK