Python中的"from some_module import *"在Lua中的用法

在Python中,我可以写from my_module import *,这样,my_module的所有成员都可以在本地作用域中使用。例如:

我的模块定义:

my_module = {}
my_module.a = 1
my_module.b = 2

在另一个文件中使用:

from my_module import *
return a + b
#=> 3

我能在Lua中这样做吗?如何实现?

点赞
用户6245072
用户6245072

要在本地范围内获取这些值,您唯一的选择就是实际上为它们命名:

--in main.lua
local mymodule = require("mymodule")
local a, b = mymodule.a, mymodule.b

--in mymodule.lua
return {a = 1, b = 2}

或者,另一种选择是:

--in main.lua
local a, b = table.unpack(require("mymodule"))

--in mymodule.lua
return {1, 2}

如果您不想实际上为它们命名,那么唯一的方法是将它们放在全局范围内。以下是两个示例:

--Python的from mymodule import *
--in main.lua
require("mymodule")
print(a + b)

--in mymodule.lua
a, b = 1, 2

--Python的import mymodule
--in main.lua
require("mymodule")
print(mymodule.a + mymodule.b)

--in mymodule.lua
mymodule = {a = 1, b = 2}

这些都是有效的方法,但最常用和安全的是第一种。

另一种可能性是尝试通过修改 _ENV 值来更改环境:

--Python的from mymodule import *
--in main.lua
local _ENV = require("mymodule")

--in mymodule.lua
return {a = 1, b = 2}

但是,通过更改环境,您将无法访问全局范围内的所有变量(除非您预先将它们声明为本地变量(local print = print; _ENV = require("mymodule"); print(a);),或者您将 _G 表中的所有变量复制到从 mymodule 返回的表中),这通常不是一件好事。

2016-08-23 07:29:08
用户2505965
用户2505965

这并不完全可行,因为修改 local 值(debug.setlocal 不能定义_新_的局部变量)并不完美。最好的办法是调整你的_环境_,因为污染全局作用域并不是一个好主意,但这并不是非常容易的。

如果仔细地做的话,这实际上可以有些优美地实现。我说是有些,因为总会有一个警告,你必须手动调整你在的函数/块的环境。在 Lua 5.2+ 中,需要 local _ENV = ...。在 Lua 5.1 中,setfenv(1, ...) 将会奏效,并且在视觉上更容易。

接下来,我们可以这样做。我们首先定义一个返回克隆环境的函数。其中 clone 是一个浅表复制函数。

return function (env)
    env = clone(env or _G)

    return env
end

接着,我们添加自定义的 import 函数,它直接修改我们的新环境,而不像 require 那样返回任何东西。你可以在这里进行很好的复杂化,实现不同的方式来决定如何导入环境,以及如何导入 ('*',例如)。

-- @module: import.lua
return function (env)
    env = clone(env or _G)

    function env.import (modname, ...)
        local args = { ... }
        local m = require(modname)

        for _, name in next, args
            env[name] = m[name]
        end
    end

    return env
end

我们可以这样使用:

local _ENV = require('import')()
-- setfenv(1, require('import')())

import('module_name', 'a', 'b')

return a + b

在小规模上,这需要相当多的开销,只是为了避免这样做:

local module_name = require('module_name')
local a, b = module_name.a, module_name.b

在更大的文档中,它可能会更有用,有很多的导入。导入通常集中在文档的顶部,所以额外的噪音并不那么糟糕。如果你可以将 env 设置为全局值一些地方,看起来会更干净。

local _ENV = env()

import('webserver', 'open', 'status', 'close')
import('database', 'connect', 'query', 'disconnect')
import('json', 'parse', 'stringify')
...

并且也可以用来创建沙箱,假设在重写 import 函数时不使用 require

local my_env = env { print = print }
my_env.import('my_mod', 'foo', 'bar')

local chunk = loadfile('my_file.lua', 'bt', my_env)
2016-08-24 02:56:14