Python通过lupa调用Lua时传入table类型报错cannot mix objects如何解决

test.lua

function test1(params)
	print(type(params),params)
    return 'test1:'..params
end

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

test.py

# -*-coding:utf-8-*-

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=LuaRuntime() table_data=lua.eval(’{ a=1, b=2 }’) print(type(table_data),table_data) #(<type ‘lupa._lupa._LuaTable’>, <Lua table at 0x2243be0>)

executor1 = Executor('test1',"hello world")     #正常,python 的字符串格式,在 lua 中也是字符串,输出:string  hello world
executor2 = Executor('test1',{"a":1,"b":2})     #正常,python 的字典格式转化成 lua 的 userdata 类型,输出:userdata    {'a': 1, 'b': 2}
executor3 = Executor('test1',table_data)        #报错,将 lua 的 table 的地址传入,输出:cannot mix objects from different Lua runtimes

executor1.start()
executor2.start()
executor3.start()
executor1.join()
executor2.join()
executor3.join()


现在是有两个问题,解决任意一个都可以。。
一个是,lua 怎么可以把,userdata 类型转化成 table 类型
另一个是,传入 table 类型的变量,为什么会报错。。

我已经把 5.1 和 5.3 的版本都试过了,都报同一个错。。。 第一次发帖就提问。。不知道也可以留个言。。


Python通过lupa调用Lua时传入table类型报错cannot mix objects如何解决

6 回复

如果是我就用 json 传参数,管你两边是什么数据类型。


这个问题我遇到过。当你在Python里用lupa往Lua函数传Python字典(或者Lua那边期待table)时,如果字典里同时有字符串键和整数键,LuaJIT(lupa的后端)就会报“cannot mix objects”这个错。这是因为Lua的table实现里,数组部分(整数键)和哈希部分(其他类型键)是分开的,而lupa在转换时处理不了这种混合类型。

核心原因:Lua的table在内部对连续整数键(如1,2,3)和字符串/非连续键的处理方式不同。lupa在将Python字典转换为Lua table时,如果遇到混合键类型,内部转换逻辑会冲突。

解决方案:在传入前,把Python字典里所有的键都转成字符串(或都转成整数,但通常转字符串更安全)。下面是个例子:

import lupa
from lupa import LuaRuntime

lua = LuaRuntime(unpack_returned_tuples=True)

# 会报错的字典:混合了字符串键和整数键
problem_dict = {
    "name": "test",
    1: "value1",  # 整数键
    "key2": "value2"
}

# 解决方案:将所有键转换为字符串
safe_dict = {str(key): value for key, value in problem_dict.items()}

# 现在可以安全传递了
lua_code = """
function process_table(tbl)
    print(tbl["name"])
    print(tbl["1"])  -- 注意:原来的整数键1现在要用字符串"1"访问
    print(tbl["key2"])
end
"""

lua.execute(lua_code)
lua_func = lua.globals().process_table
lua_func(safe_dict)  # 正常执行

如果你需要保持Lua那边能用整数索引访问,那就得在构造字典时避免混合类型,或者分两个table传。

简单说:传之前把字典键全转成字符串就完事了。

不懂 lupa。 但是两个 lua 环境肯定不能直接传递表对象的吧, 就好像两个进程不能相互传递指针一样。 传递数据需要先序列化。

userdata 是进程内的一块连续内存,table 是 lua 环境下的表结构,两个不同的数据类型, 不能直接转换。想把 userdata 里的数据读出来的话, 需要自定义元表方法。

今天了解到,两个 python 进程间共享内存的还是 RPC。。。。想确认一件事,“自定义元表方法"可以用纯 lua 实现吗?还是中间还需要 C 语言??

操作 userdata 用 C




想到一个方法,python 通过 rpc 共享 json,lue 调用 rpc 拿 json 数据。。。
感觉还不如 redis。。

回到顶部