Python调用Lua:Lupa

lua与python均为成熟的脚本方案,它们的不同在与体量,Lua的体量小,高效的执行方式适合嵌入式,python胶水的强大不言而喻。那么如果自己已经有了lua脚本的解决方案,python能否调用呢?答案是肯定的,这篇博客将介绍python中集成的lua环境包:lupa,简单介绍该工具的使用。

一、安装lupa

在线安装: pip install lupa

离线安装:下载离线包 https://pypi.org/project/lupa/#files

选择对应平台的离线包下载后使用pip进行安装

二、使用lupa再python中执行lua语句

lua.eval 可以直接执行lua语句

>>> from lupa import LuaRuntime 
>>> lua = LuaRuntime() 
>>> lua.eval('1+1') 

三、python中调用lua函数

Lupa将LuaJIT集成到了Python模块中,可以在Python中执行Lua代码。

下面提供一个.py 调用 .lua 中函数的demo,其中使用了lua的回调函数。如果只是需要简单函数,只需要在变量 g 中 按照名字找到函数的映射就可以了。

Test.lua


function test1(params)
    return 'test1:'..params
end

function test2(params)
    return 'test2:'..params
end

-- 入口函数,实现反射函数调用
function functionCall(func_name,params)
    local is_true,result
    local sandBox = function(func_name,params)
        local result
        result = _G[func_name](params)
        return result
    end
    is_true,result= pcall(sandBox,func_name,params)
    return result
end

Test.py

import traceback
from lupa import LuaRuntime
import threading

class Executor(threading.Thread):
    """
        执行lua的线程类
    """
    lock = threading.RLock()
    luaScriptContent = None
    luaRuntime = None

    def __init__(self,api,params):
        threading.Thread.__init__(self)
        self.params = params
        self.api = api

    def run(self):
        try:
            # 执行具体的函数,返回结果打印在屏幕上
            luaRuntime = self.getLuaRuntime()
            rel = luaRuntime(self.api, self.params)
            print rel
        except Exception,e:
            print e.message
            traceback.extract_stack()


    def getLuaRuntime(self):
        """
            从文件中加载要执行的lua脚本,初始化lua执行环境
        """

        # 上锁,保证多个线程加载不会冲突
        if Executor.lock.acquire():
            if Executor.luaRuntime is None:
                fileHandler = open('./test.lua')
                content = ''
                try:
                    content = fileHandler.read()
                except Exception, e:
                    print e.message
                    traceback.extract_stack()

                # 创建lua执行环境
                Executor.luaScriptContent = content
                luaRuntime = LuaRuntime()
                luaRuntime.execute(content)

                # 从lua执行环境中取出全局函数functionCall作为入口函数调用,实现lua的反射调用
                g = luaRuntime.globals()
                function_call = g.functionCall
                Executor.luaRuntime = function_call
            Executor.lock.release()

        return Executor.luaRuntime


if __name__ == "__main__":

    # 在两个线程中分别执行lua中test1,test2函数
    executor1 = Executor('test1','hello world')
    executor2 = Executor('test2','rudy')
    executor1.start()
    executor2.start()
    executor1.join()
    executor2.join()

在使用 g.function 直接调用lua函数的时候,返回值就直接是 lua脚本 中的返回值,还是非常友好的,如果遇到table返回值,在python中类型就是luaTable,直接按照下标索引就可以了。

四、lua调用python

由于lua中不能出现python的变量,所以lua调用python只能使用lua.eval来执行一个匿名的定义,建立一个函数映射关系,来进行调用。

下面这个demo中的 lua.eval 就是返回一个lua_call 到 py_call 的映射

import lupa
from lupa import LuaRuntime
lua = LuaRuntime(unpack_returned_tuples=True)

def py_func(p):
    print p
    return 'hello '+str(p)

#execute无返回,打印出来是None
lua.execute('var_before=1;print(var_before);')

#eval返回的是一个lua call到py call的映射
pycall = lua.eval('function(pyfunc,param1) var_before=pyfunc(param1) end')

pycall(py_func,'world') # 打印world,返回的var_before = hello world

lua.execute('print(var_before)') # 打印 hello world

下面的这个例子也是类似的

>>> from lupa import LuaRuntime 
>>> lua = LuaRuntime() 
>>> lua.eval('1+1') 
>>> lua_func = lua.eval('function(f, n) return f(n) end') 
>>> def py_add1(n): return n+1 
>>> lua_func(py_add1, 2) 
>>> lua.eval('python.eval(" 2 ** 2 ")') == 4    #True 
>>> lua.eval('python.builtins.str(4)') == '4'   #True

多找一些开源社区吧,相关的资料还是挺多的。

发表评论