簡體   English   中英

將python腳本添加到非python應用程序的“正確”方法

[英]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] = [...]技巧)。

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通知應用程序,例如名稱描述功能期望 ,基本上通知應用程序它是什么,以及它將要做什么。

我沒有看到嵌入Python的問題,例如Boost.Python。 你會得到你要求的一切:

  • 它將被嵌入,它將是一個解釋器(有足夠的訪問權來實現自動完成等)
  • 您可以為每個腳本創建一個新的解釋器,並完全分離python環境
  • ......並且盡可能透明

我的意思是,你仍然需要公開和實現一個API,但1)這是一件好事,2)Blender也做了這件事3)我真的想不出另一種方法可以利用你的工作...... 。

PS:我對Python / Boost.Python沒什么經驗,但是和Lua / LuaBind一起工作很廣泛,這有點相同

如果您真的想為您和您的用戶盡可能地輕松,請考慮擴展python而不是嵌入。

  • 嵌入不允許與其他軟件輕松集成 - 只有一個嵌入python的程序可以通過python腳本一次使用。 OTOH擴展意味着用戶可以在python運行的任何地方使用您的軟件;
  • 要使腳本編寫器可以使用其他內容,您不必初始化解釋器。 解釋器將為您初始化,為您節省工作。
  • 您不必創建特殊的內置變量和偽模塊來注入嵌入式解釋器。 只需給它們一個真正的擴展模塊,就可以在首次導入模塊時初始化所有內容。
  • 您可以使用distutils來分發您的軟件
  • 像virtualenv這樣的工具可以按原樣使用 - 您或用戶不必提供新工具。 您的用戶還可以使用她選擇的IDE /調試工具/測試框架

嵌入確實不會給您和您的用戶帶來任何好處。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM