呼叫python - python转c++




将python脚本添加到非python应用程序的“正确”方法 (2)

如果您真的想为您和您的用户尽可能地轻松,请考虑扩展python而不是嵌入。

  • 嵌入不允许与其他软件轻松集成 - 只有一个嵌入python的程序可以通过python脚本一次使用。 OTOH扩展意味着用户可以在python运行的任何地方使用您的软件;
  • 要使脚本编写器可以使用某些内容,您不必初始化解释器。 解释器将为您初始化,为您节省工作。
  • 您不必创建特殊的内置变量和伪模块来注入嵌入式解释器。 只需给它们一个真正的扩展模块,您就可以在首次导入模块时初始化所有内容。
  • 您可以使用distutils来分发您的软件
  • 像virtualenv这样的工具可以按原样使用 - 您或用户不必提供新工具。 您的用户还可以使用她选择的IDE /调试工具/测试框架

嵌入确实不会给您和您的用户带来任何好处。

我目前正在使用python中编写的插件为用户添加扩展桌面应用程序(C ++)功能的能力。

天真的方法很简单。 嵌入python静态库并按照分散在Web上的任意数量的教程来描述如何初始化和调用python文件,并且你已经完成了很多工作。

然而...

我正在寻找的更像是Blender所做的。 Blender可以通过python脚本完全自定义,它需要一个外部 python可执行文件。 (即,python实际上并没有嵌入到blender可执行文件中。)因此,当然,在编写blender脚本时,可以包含site-packages目录中已有的任何模块。 不是那个建议,因为这会限制脚本的可移植性。

所以,我想知道的是,如果已经有办法让你的蛋糕也吃了它。 我想要一个使用以下内容的插件系统:

  • 嵌入式python解释器。

    Blender的方法的缺点是它迫使你在你的系统上全局安装一个特定的,可能过时的python版本。 有一个嵌入式解释器允许我控制正在使用的python版本。

  • 防火墙插件。

    相当于每个插件的virtualenv ; 允许他们安装他们需要或想要的所有模块,但要将它们与其他插件中的可能冲突分开。 也许zc.buildout在这里是一个更好的候选人,但是,我再次非常 zc.buildout接受建议。 对于实现这一目标的最佳方式,我有点不知所措。

  • 尽可能无痛......

    对于用户。 只要上面的大部分内容对插件编写者尽可能透明,我愿意加倍努力。

如果你们中的任何人有这方面的经验,你们的帮助将不胜感激。 :)

编辑:基本上,我想要的简短版本是virtualenv的简单,但没有捆绑的python解释器,以及一种以编程方式激活特定“虚拟环境”的方法,如zc.buildout与sys.path操作( sys.path[0:0] = [...]技巧)。

virtualenvzc.buildout都包含我想要的部分内容,但是它们都不会产生可重定位的构建,我或者插件开发人员可以简单地压缩并发送到另一台计算机。

简单地操作.pth文件,或直接在脚本中操作sys.path ,从我的应用程序执行,让我在那里中途。 但是,当编译模块是必要的时候,例如PIL,这还不够。


实现此目标的一种有效方法是使用消息传递/通信流程体系结构,允许您使用Python实现目标,但不限制自己使用Python。

------------------------------------
| App  <--> Ext. API <--> Protocol | <--> (Socket) <--> API.py <--> Script
------------------------------------

此图试图显示以下内容:您的应用程序使用消息传递与外部进程(例如Python)通信。 这在本地计算机上很有效,并且可以移植,因为您定义了自己的协议 。 您必须为用户提供的唯一功能是实现自定义API的Python库,并使用用户脚本和应用程序之间的Send-Receive通信循环进行通信。

定义应用程序的外部API

应用程序的外部API描述了外部进程必须能够与之交互的所有功能。 例如,如果您希望Python脚本能够在应用程序中绘制红色圆圈,则外部API可能包括绘图(对象,颜色,位置)。

定义通信协议

这是外部进程通过其外部API与您的应用程序通信的协议。 流行的选择可能是XML-RPC,SunRPC,JSON或您自己的自定义协议和数据格式。 这里的选择需要足够您的API。 例如,如果要传输二进制数据,则JSON可能需要base64编码,而SunRPC则采用二进制通信。

构建应用程序的消息系统

这就像在通信协议中接收消息的无限循环一样简单,为应用程序内的请求提供服务,并通过相同的套接字/通道进行回复。 例如,如果您选择JSON,那么您将收到一条消息,其中包含执行Draw(对象,颜色,位置)的指令。 执行请求后,您将回复该请求。

为Python(或其他任何东西)构建消息传递库

这甚至更简单。 同样,这是一个代表库用户发送和接收消息的循环(即您的用户编写Python脚本)。 该库必须做的唯一事情是为应用程序的外部API提供编程接口,并将请求转换为您的通信协议,所有这些都隐藏在您的用户之外。

例如,使用Unix套接字将非常快。

插件/应用程序Rendezvous

发现应用程序插件的常见做法是指定应放置插件的“众所周知”目录。 例如,这可能是:

~/.myapp/plugins

下一步是让您的应用程序查看此目录中是否存在插件。 您的应用程序应该有一些智能,以便能够区分适用于您的应用程序的实际脚本的Python脚本。

假设您的通信协议指定每个脚本将使用JSON通过StdInput / StdOuput进行通信。 一种简单有效的方法是在您的协议中指定脚本第一次运行时将MAGIC_ID发送到标准输出。 也就是说,您的应用程序会读取第一个,例如8个字节,并查找将其标识为脚本的特定64位值。

此外,您应该在外部API方法中包含允许脚本标识自己的方法。 例如,脚本应该能够通过外部API通知应用程序,例如名称描述功能期望 ,基本上通知应用程序它是什么,以及它将要做什么。





desktop-application