检测 Lua 脚本是被导入还是被直接执行

在 Python 中,有一种常见的形式 if __name__ == "__main__":,用于检测文件是被导入还是被直接执行。通常,在这个条件语句中所执行的唯一操作就是 执行某些 "合理、顶层" 函数。这允许相同的文件可用作基本脚本和库模块 (也可以作为交互式用户可以导入和使用的东西)。

我想知道在 Lua 中是否有一种干净和可靠的方法来做到这一点。我认为我可以使用 _REQUIREDNAME 全局变量,但这在 Lua 5.1 中已被更改。目前,Lua 的 require 会传递参数 (在可变参数 ... 中),因此原则上这些参数可以被检查。但是,这要么不可靠,要么不干净,或者两者都是,因为很明显当脚本被执行时可以传递参数。所以要安全地做到这一点,你必须检查这些参数。

顺便说一下,require 会将模块名称作为第一个参数 (你调用 require 的字符串) 并将其找到的文件的路径作为第二个参数传递。因此,可以进行一些检查来尝试检测这一点,不过这并不像 if __name__ == "__main__": 那样好,而且用户总是可以通过传递两个合适构造的参数来绕过它。这并不是一种安全威胁,但我希望有更好的解决方案。

我还尝试了另一种方法,我觉得非常丑陋但很有前途。这是使用 debug.traceback()。如果脚本是被直接执行的,那么返回的跟踪信息非常可预测,实际上只有 3 行。我认为这可能就是解决方案,尽管像我说的那样,这是一种丑陋的破解方法。

有没有更频繁地使用 Lua 的用户可以提供建议呢?事实上,如果我正在编写模块 X,我想在脚本模式下返回 X.main_func() 或者在导入模式下返回 X

编辑: 我删掉了一个其实是错误的项目 (使我的 traceback 解决方案可行)。此外,Egor Skriptunoff 在评论中提供的链接提供了 debug 库中的另一个技巧,它比使用 traceback 更干净。除此之外,似乎每个人都遇到了与我相同的问题,而且 Lua 团队对提供官方支持此功能并不感兴趣。

点赞
用户1902885
用户1902885

根据 Egor 提供的链接,目前最清洁和安全的做法似乎是以下示例:

如何确定我的代码是否在 Lua 模块中运行?

我在此重复一下以供参考:

if pcall(debug.getlocal, 4, 1) then
  print("in package")
else
  print("in main script")
end

有一个完整的线程在这里讨论:

http://lua.2524044.n2.nabble.com/Modules-with-standalone-main-program-td7681497.html

就像我说的那样,似乎这是一个普遍的功能,暂时不受支持,但 debug.getlocal 方法似乎是普通 Lua 开发人员现在所采用的方法。

2021-05-18 06:59:02
用户11740758
用户11740758

package.loaded 中返回 require()

因此,可以简单地检查 package.loaded 来获取所需内容。

此外,作为更多经验的良好起点,建议编写 package.preload 函数以获取 require() 的内容,而无需操作路径。

以下是一个简单的示例...

# /usr/local/bin/lua -i
Lua 5.4.3  Copyright (C) 1994-2021 Lua.org, PUC-Rio
> package.preload.mymod=function() return {dump=function(...)
>> local args={...}
>> local test,dump=pcall(assert,args[1])
>> if test then
>> for key,value in pairs(dump) do
>> io.write(string.format("%s=%s\n",key,value)):flush()
>> end
>> return true
>> else
>> return test,dump
>> end
>> end} end
> mymod=require('mymod')
> mymod.dump(package.loaded)
string=table: 0x56693590
mymod=table: 0x566aa890
utf8=table: 0x56694d80
package=table: 0x56691ed0
math=table: 0x56693cb0
table=table: 0x566920d0
_G=table: 0x56690730
debug=table: 0x566950e0
coroutine=table: 0x56692310
os=table: 0x56692e60
io=table: 0x566921b0
true
2021-05-18 07:25:20