本文讨论了在Python插件开发中,如何封装和管理通用的Python方法以便复用。介绍了“CV技能”复制粘贴方法的不足,并提出了将Python方法封装成代码文件,通过exec指令或IronPython引擎动态加载执行。进一步分析了IronPython的运行原理,并说明了如何封装Python插件库,以便其他插件(包括C#插件)调用。还讨论了将封装好的Python插件方法开放成外部WebAPI接口,以及如何实现这些功能。最后,总结了该方案的优势,并提到可以作为Python代码管理工具,实现代码共享和协同开发。
一、业务背景
小伙伴们实践了Python插件开发后,觉得很方便,如果你擅于代码封装,就会形成许多通用的插件方法,那这些插件方法如何快速复用呢?
目前采用的是"CV技能"(复制粘贴),把曾经封装过的Python插件方法复制过来使用,基于Python插件的便利性,这也是很不错的!
但是,这也会有一些缺点,不方便统一管理这些通用的代码,如果方法里面后续发现了BUG或者需要完善,有可能需要对很多个复制使用这个方法的插件中都修改!
如果会C#插件开发的同学就知道,通用的插件代码,我们可以封装成dll库,然后添加到不同的插件工程中来进行引用!
Python插件运维迭代起来非常方便快捷,能不能把一些通用的Python方法封装成代码文件,提供给其他地方调用呢?
不用怀疑,当然是可以的,Python作为脚本语言,可以动态加载使用,甚至可以直接通过exec指令,直接执行代码中把Python脚本的字符串,
就像 @请输入昵称___老师 分享的这个案例:#使用技巧# 开发个Python在线测试功能
也就是说,我们可以把要执行的Python代码,作为字符串传递给exec执行,至少这是一种可行的实现思路!
还有其他方法吗?可以再深入思考一下,我们在BOS里面注册Python脚本之后,系统是如何运行的呢?
我们知道,Python插件开发并不是原生的Python开发,而是IronPython,这个在第1篇文章就给大家介绍过了,IronPython是.NET平台用来解释执行Python脚本的,系统运行我们注册的Python脚本时,也是回到.NET平台通过IronPython引擎来执行的,这也是C#的插件可以用Python来开发的核心支撑,主要是以下2个dll库来完成的:
(IronPython的具体实现原理和这2个dll库的用法,大家可以自行查询资料了解更多信息)
IronPython.dll
Microsoft.Scripting.dll
实际上,Python插件的本质是用Python语法来调用.NET库来实现开发的,也就是说我们可以在Python插件中调用上面的2个dll库,基于这个原理,我们封装好的Python插件代码,不仅通过C#插件中能调用,在Python插件也可以调用!
基于以上思路分析, 我们就可以封装自己的Python插件库,然后提供给其他地方调用了,可以包括以下几种场景:
其他插件调用封装好的Python插件方法(Python插件和C#插件均可)
封装好的Python插件方法,开放成外部WebAPI接口,可以快速定制各种自定义WebAPI接口,并且运维迭代方便。
(基于此案例思路:#实践案例#Python插件变通实现自定义WebAPI接口查询报表)
C#插件执行计划插件调用封装好的Python插件方法(虽然Python插件不能直接开发执行计划插件,这也能便通过实现了)
二、解决方案
首先,如何对封装好的Python代码文件进行管理?放到固定文件夹?数据库?
这里选择的存到服务器一个自定义的文件夹下面,这个文件夹我们可以根据WebSite的相对路径来自动识别,建议放到WebSite的同级目录,方便查找,并且不在IIS站点目录下,与IIS服务不会相互影响!
然后我们开发一个简单的单据来作为文件上传入口,记录文件的保存路径:
上传代码文件->单据保存自动将上传的文件移动到固定的文件路径->删除单据也可以自动删除该文件!
代码查看,上传后的代码文件,可以支持在线查看和复制
(由于Python代码缩进格式敏感,暂不开发在线编辑功能,可用记事本编辑保存后重新上传)
解析Python代码文件,将代码文件中的方法以及参数解析出来,然后录入方法和参数说明,Python插件库就更完善了!
如果解析报错,说明上传的代码文件有问题,则需要检查修改之后重新上传,这样相当于也有了一个代码检查的功能,保证代码文件的可靠性!
方法调用,动态调用Python代码文件的关键代码就在这里
其他插件要调用方法时,就可以用这样的代码写法来调用Python代码文件中的方法,这里分享一下如何调用Python代码文件的核心代码!
前面提到了有2种方式可以动态执行Python代码:exec指令、IronPython引擎
①exec指令,我验证过也能用,这里简单介绍一下!
(我后面实际选择的是使用IronPython引擎,用IronPython更方便解析Python代码方法签名)
exec其实就是把一段Python代码的字符串直接执行,类似于执行SQL语句,当然对于执行过程也可以传参和获取返回值,大家可以查询exec的相关资料!
这里有2种思路:一种是直接封装方法代码,然后把调用方法的代码拼接成字符串来调用
另一种是直接封装Python类,然后通过类对象来调用方法(定义静态方法,可以省略self参数),这种思路似乎更好一点!
②通过IronPython引擎来动态执行Python代码文件!核心重点代码来了...
首先,根据Py代码文件路径,通过IronPython引擎解析得到一个ScriptScope(脚本作用域)
I.如果是插件代码调用,可以直接通过: 作用域.方法名(...), 可直接调用固定方法,并传入固定的匹配参数,和通过类名调用静态方法的写法类似了!
#...前面如何获取Py代码库文件的路径PyFileFullName就很简单了,省略... pythonClassScope=getPyClassInfo(PyFileFullName); BillFormId="BD_Material"; allFlds=pythonClassScope.GetALLFiedInfoByFormId(this.Context, BillFormId);
II.也可以通过方法名的字符串动态调用(开放到WebAPI接口调用时需要动态传方法名和动态传递参数),此时注意方法参数列表传递的处理方式,有2种方式
#①借助exec来调用,方法名和参数列表都是拼接成字符串 retObj=None;#声明一个变量接收返回值 exec("retObj=pythonClassScope.GetALLFiedInfoByFormId(this.Context, BillFormId);"); #②(推荐)先根据方法名从Scope中获取到Py方法对象,然后再调用 pythonClassScope=getPyClassInfo(PyFileFullName); methodName="GetALLFiedInfoByFormId"; onePyFun=getPyFun(pythonClassScope,methodName);#onePyFun就代表方法名对应的方法对象 retObj=onePyFun(this.Context, BillFormId); #如果参数列表也是动态匹配的,Py插件调用时,可使用Python里面的"*"号的解包用法传参(可自行查询相关用法) funParas=[];#先把参数按顺序构造到一个列表中,通常是循环某个数据来源,WebAPI接口动态调用时,使用此写法封装调用过程 funParas.append(this.Context); funParas.append(BillFormId); retObj=onePyFun(*funParas);#调用方法
WebAPI接口调用,对Python插件库封装接口调用触发的功能
基于前面发布的这个案例的思路:#实践案例#Python插件变通实现自定义WebAPI接口查询报表
实现原理类似,不过多叙述,核心就是根据Python代码文件解析的方法,配置参数列表->指定参数类型->生成调用的JSON参数格式
然后开发一个通用的保存服务插件,按上述使用方法名动态调用的逻辑来执行方法,然后返回方法的返回值即可!
三、实现效果演示
(这里主要演示一下WebAPI调用Python插件库的效果)
四、总结几点
基于以上原理,可以把常用的Python插件方法分类封装成插件库,然后其他地方可以通过获取这个Python文件来调用。
执行计划插件也能调用,可用C#封装一个通用的执行计划插件,在Run方法里面调用指定的Py方法即可,这样就能变通用Python来开发定时任务,而且维护方便。
如果封装给WebAPI调用的方法,由于接口数据交互是以JSON的形式,要注意参数类型最好是普通数据类型(文本、数字、JSON对象等),并且返回值也最好是字符串,复杂对象可以序列化成JSON字符串返回。
插件方法中经常会用到Context,要把这个提取出来,作为方法参数传入,不可直接在Py插件库的方法中访问this.Context。
这个Python插件库建立起来之后,可以作为自己的一个Python代码管理工具,并且可以做一些更精准的搜索功能,可以快速的查找想要的代码。
基于这个Python插件库的建立,可以进一步实现Python插件开发协同,甚至可以通过git等平台来实现Python插件代码共享、快速复用。
==============================正文结束=====================================
感谢大家的关注与评阅,希望能为大家的实际问题带来参考和启发。
此方案全部用Python插件实现,如果需要此方案的二开补丁或者完整源码,可私信作者!
发布于 金蝶云星空BOS开发交流圈 社群
推荐阅读