【问题标题】:Detect Whether Script Was Imported or Executed in Lua检测脚本是否在 Lua 中被导入或执行
【发布时间】:2021-05-18 03:42:18
【问题描述】:

在python中,有一个常见的if __name__ == "__main__":形式的构造来检测文件是被导入还是直接执行。通常,在这个条件中采取的唯一行动是执行一些“明智的、顶级的”功能。这允许将同一个文件用作基本脚本和库模块(也可以作为交互式用户可以导入和使用的东西)。

我想知道在 lua 中是否有一种干净可靠的方法可以做到这一点。我以为我可以使用 _REQUIREDNAME 全局变量,但事实证明这在 Lua 5.1 中已更改。目前,lua require 传递参数(在可变参数... 中),因此原则上可以检查这些参数。但是,这要么不可靠,要么不干净,或者可能两者兼而有之,因为显然在执行脚本时可以传递参数。因此,要安全地执行此操作,您必须检查参数。

FWIW,require 将模块名称作为参数 1(您调用 require 的字符串)传递,并将它最终找到的文件的路径作为参数 2。所以显然可以进行一些检查尝试检测这一点,如果它不如if __name__ == "__main__": 好,并且用户总是可以通过向脚本传递两个适当构造的参数来绕过它。不完全是安全威胁,但我希望有更好的解决方案。

我还尝试了另一种方法,我发现它非常丑陋但很有前途。这是使用debug.traceack()。如果直接执行脚本的话,traceback 是非常可预测的,其实只有 3 行。我想这可能是它,虽然,就像我说的,一个丑陋的黑客肯定。

有更多频繁使用 lua 的用户有什么建议吗?实际上,如果我正在编写模块 X,我想要么在脚本模式下使用 return X.main_func(),要么在导入模式下使用 return X

编辑: 我取出了一个实际上不正确的项目(并使我的回溯解决方案可行)。此外,Egor Skriptunoff 在评论中提供的链接确实提供了调试库中的另一个技巧,它甚至比使用回溯更干净。除此之外,似乎每个人都遇到了和我一样的问题,而 lua 团队一直对提供官方手段来支持这一点不感兴趣。

【问题讨论】:

标签: lua


【解决方案1】:

根据 Egor 提供的链接,目前最干净、最安全的方法似乎如下所述:

How to determine whether my code is running in a lua module?

为了方便参考,我重复一遍:

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 开发人员目前已经解决的问题。

【讨论】:

    【解决方案2】:

    一个require()返回package.loaded
    所以只需检查你想要的 package.loaded。

    作为获得更多经验的良好开端,我建议在不操纵路径的情况下为 require() 编写 package.preload 函数。
    一个简单的例子来展示这个......

    # /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
    

    【讨论】:

    • 谢谢,如果我记得我确实看过这个,但我认为 package.loaded 在脚本运行之前是 nil,所以脚本本身不知道是直接执行还是通过 require 执行。我不想编写自己的修改作为解决方案,因为那样它将在另一个平台上失败。
    猜你喜欢
    • 2011-07-20
    • 2015-04-19
    • 2017-09-08
    • 2011-08-18
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多