官方原文: 【插件开发】使用 Python 扩展 UiBot 的功能
主要步骤
- 在
uibot
安装目录下面的extend\python
中放置xxx.py
文件即可在uibot
中使用import xxx
引入定义的函数使用.
- 官方包在安装目录的
lib\site-packages
下, 如果不够用就需要自己复制粘贴过来. 当然更棒的方法是用pip直接装到这个目录下, 加上--target=
即可:Pip install gooey --target="D:\myprog\UiBot Creator Community 5.5.0 (x64)\lib\site-packages"
两者传参和返回值的测试
- 所以如果在py中定义了新的函数, 或者修改了形参数量需要在uibot中调用, 则需要重启creator. 因为py中def的函数名和形参是在启动creator的时候加载的, 然而函数体是实时从py函数体中调用的.
- py返回值中, int/float/string/list/dict/tuple类型都能正确识别,请知tuple是被当做list识别的. 但
type
类型不能识别, 所以不能return type(1)
, 需要转为string: str()
- py形参中, 从uibot串入的int/float/str/list/dict都能正确识别.
- py中的
print
并不能输出到uibot的输出窗口.
- python的内置库和第三方库都是不能直接'import'的, 需要写个py中转一下
从Uibot注入Python代码直接运行 (简版)
定义一个中转py,命名为run.py
, 如下:
def e(func, runfunc):
exec(func)
return eval(runfunc)
第一个参数由exec()执行,没有返回值, 适合定义函数. 第二个参数由eval执行, 有返回值, 适合运行函数.
在uibot中直接运行python代码, 例如:
Import Run
Log.Info(Run.e("def add(a, b):\n return a+b", "add(1,2)"))
将会返回3
这样就不需要对uibot开开关关的了, 可以直接调试. 另外也不需要再跑到extend\python
中去更新py文件.
从Uibot注入Python代码直接运行 (强化版)
上面的简版无法从Uibot中读取变量, 下面这个版本则解决这个问题
# p = { # params
# g:{}, # eval(,g,)
# l:{}, # eval(,,l)
# f:['functionName1', 'functionName2'...], # function names from exec()
#}
def e(func, runfunc, p):
exec(func)
if 'g' in p:
if 'f' in p:
for fn in p['f']:
p['g'][fn] = eval(fn)
if 'l' in p:
return eval(runfunc, p['g'], p['l'])
return eval(runfunc, p['g'])
return eval(runfunc)
解释: 增加了一个参数p, 用于给eval输入Uibot的变量. eval支持globals和locals变量的输入, 这儿都给用上了, 分别是p['g']
和p['l']
. 按eval
要求p['g']
必须是一个dict,也即是{}
要注意的是, 输入的变量会冲掉以前的变量, 也就是在exec
中定义的函数名也会被globals完全替代掉, 所以如果要用globals就必须重新在globals中引入函数名, 所以又增加了p['f']
来输入函数名字符串的数组, 并将其用eval(fn)
转换为真正的函数地址,输入给p['g']
必须要注意的是python的dict的子元素key的引用必须用数组形式加引号如p['f']
, 这有时候显然不如js方便p.f
在uibot中直接运行python代码:
ret= Run.e('def add(a,b):\n return a+b', 'add(x,y)',{'f':['add'], 'g':{'x':1,'y':2}} )
Log.Info(ret)
显示-1
从Uibot注入Python代码直接运行 (强化版V2.0)
然而上面这样的调用方式还是很麻烦, 有没有更加简单的?
然而不管怎么试, 都没有办法做到直接在Uibot里面运行add(1,2)
这样的形式, 从Python返回的函数指针到了Uibot里只被认作一个普通的python对象, 如果用Type查看, 居然还是String类型, 而不是function类型.
曲线救国的方式, 在res目录下新建三个文件, 分别是:
func.py
def add(a, b):
return a + b
runfunc.py
add(a1, a2)
p.json
{
"f": ["add"],
"g": {"a1": 1, "a2":2},
"l": {}
}
然后新建一个公共流程块命名为pub, 内容如下:
/*
语法糖, 可以让Uibot实时调用func.py中动态定义的函数, 如add, 形式为:
run.e("add", [1,2])
funcName: string,
funcParam: arr.
*/
Function e(sFuncName, arrFuncParam)
Import run
sFunc = File.Read(@res"func.py","auto")
sRunFunc = sFuncName & "("
dictP = {"f": [sFuncName],
"g": {} }
//组装成 funcName(a1,a2,a3...)这样的形式
For i=1 To Len(arrFuncParam)
sRunFunc = sRunFunc & 'a' &CStr(i)
dictP['g']['a' &CStr(i)] = arrFuncParam[i-1]
If Len(arrFuncParam) = i
sRunFunc = sRunFunc & ')'
Else
sRunFunc = sRunFunc & ','
End If
Next
Return Run.e(sFunc, sRunFunc, dictP )
End Function
/*
直接运行在func.py, runfunc.py p.json中定义的函数及参数
*/
Function py()
Import run
sFunc = File.Read(@res"func.py","auto")
sRunFunc = File.Read(@res"runfunc.py","auto")
dictP = JSON.Parse(File.Read(@res"p.json","auto"))
Return Run.e(sFunc, sRunFunc, dictP )
End Function
这样在普通的流程块里就可以这样调用了:
pub.e("add",[1,2])
虽然和add(1,2)
有些差距, 但怎么说都舒服多了不是. 也可以完全从文件调用:
pub.py()
Uibot和python怎么分工?
- 我觉得Uibot对界面的处理使强项, 对逻辑处理就要差很多了, 这部分用python似乎更好.
- 另外Python库很丰富, 可以扩展出很多应用.
- Uibot对用户输入的界面也比较弱. Python中有一个Gooey看起来要好用的多.