[英]The “right” way to add python scripting to a non-python application
我目前正在使用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] = [...]
技巧)。
virtualenv
和zc.buildout
都包含我想要的部分內容,但是它們都不會產生可重定位的構建,我或者插件開發人員可以簡單地壓縮並發送到另一台計算機。
簡單地操作.pth文件,或直接在腳本中操作sys.path
,從我的應用程序執行,讓我在那里中途。 但是,當編譯模塊是必要的時候,例如PIL,這還不夠。
實現此目的的一種有效方法是使用消息傳遞/通信流程體系結構,允許您使用Python實現目標,但不限制自己使用Python。
------------------------------------
| App <--> Ext. API <--> Protocol | <--> (Socket) <--> API.py <--> Script
------------------------------------
此圖試圖顯示以下內容:您的應用程序使用消息傳遞與外部進程(例如Python)進行通信。 這在本地計算機上很有效,並且可以移植,因為您定義了自己的協議 。 您必須為用戶提供的唯一功能是實現自定義API的Python庫,並使用用戶腳本和應用程序之間的Send-Receive通信循環進行通信。
應用程序的外部API描述了外部進程必須能夠與之交互的所有功能。 例如,如果您希望Python腳本能夠在應用程序中繪制紅色圓圈,則外部API可能包括繪圖(對象,顏色,位置)。
這是外部進程通過其外部API與您的應用程序通信的協議。 流行的選擇可能是XML-RPC,SunRPC,JSON或您自己的自定義協議和數據格式。 這里的選擇需要足夠您的API。 例如,如果要傳輸二進制數據,則JSON可能需要base64編碼,而SunRPC則采用二進制通信。
這就像在通信協議中接收消息的無限循環一樣簡單,為應用程序內的請求提供服務,並通過相同的套接字/通道進行回復。 例如,如果您選擇JSON,那么您將收到一條消息,其中包含執行Draw(對象,顏色,位置)的指令。 執行請求后,您將回復該請求。
這甚至更簡單。 同樣,這是一個代表庫用戶發送和接收消息的循環(即您的用戶編寫Python腳本)。 該庫必須做的唯一事情是為應用程序的外部API提供編程接口,並將請求轉換為您的通信協議,所有這些都隱藏在您的用戶之外。
例如,使用Unix套接字將非常快。
發現應用程序插件的常見做法是指定應放置插件的“眾所周知”目錄。 例如,這可能是:
~/.myapp/plugins
下一步是讓您的應用程序查看此目錄中是否存在插件。 您的應用程序應該具有一些智能,以便能夠區分適用於您的應用程序的實際腳本的Python腳本。
假設您的通信協議指定每個腳本將使用JSON通過StdInput / StdOuput進行通信。 一種簡單有效的方法是在您的協議中指定腳本第一次運行時將MAGIC_ID發送到標准輸出。 也就是說,您的應用程序會讀取第一個,例如8個字節,並查找將其標識為腳本的特定64位值。
此外,您應該在外部API中包含允許腳本識別自身的方法。 例如,腳本應該能夠通過外部API通知應用程序,例如名稱 , 描述 , 功能 , 期望 ,基本上通知應用程序它是什么,以及它將要做什么。
我沒有看到嵌入Python的問題,例如Boost.Python。 你會得到你要求的一切:
我的意思是,你仍然需要公開和實現一個API,但1)這是一件好事,2)Blender也做了這件事3)我真的想不出另一種方法可以利用你的工作...... 。
PS:我對Python / Boost.Python沒什么經驗,但是和Lua / LuaBind一起工作很廣泛,這有點相同
如果您真的想為您和您的用戶盡可能地輕松,請考慮擴展python而不是嵌入。
嵌入確實不會給您和您的用戶帶來任何好處。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.