【问题标题】:Print all local variables accessible to the current scope in Lua打印 Lua 中当前作用域可访问的所有局部变量
【发布时间】:2011-02-19 13:06:01
【问题描述】:

我知道如何使用以下代码打印“所有”全局变量

for k,v in pairs(_G) do
    print("Global key", k, "value", v)
end

所以我的问题是如何对当前执行的函数可访问的所有变量执行此操作,这可以执行 locals() 为 Python 执行的操作。

【问题讨论】:

    标签: lua introspection


    【解决方案1】:

    这是一个locals() 函数的实现。它将从调用范围返回一个本地表:

    function locals()
      local variables = {}
      local idx = 1
      while true do
        local ln, lv = debug.getlocal(2, idx)
        if ln ~= nil then
          variables[ln] = lv
        else
          break
        end
        idx = 1 + idx
      end
      return variables
    end
    

    请注意,在 lua REPL 中,每一行都是具有单独局部变量的单独块。此外,还会返回内部变量(名称以 '(' 开头,如果要删除它们):

    > local a = 2; for x, v in pairs(locals()) do print(x, v) end
    a   2
    (*temporary)    function: 0x10359b38
    

    感谢您的接受。你已经解开了最后一块拼图! ;-)

    Upvalues 是来自外部作用域的局部变量,在当前函数中使用。他们既不在_G 也不在locals()

    function upvalues()
      local variables = {}
      local idx = 1
      local func = debug.getinfo(2, "f").func
      while true do
        local ln, lv = debug.getupvalue(func, idx)
        if ln ~= nil then
          variables[ln] = lv
        else
          break
        end
        idx = 1 + idx
      end
      return variables
    end
    

    示例(请注意,您必须使用 a 才能显示):

    > local a= 2; function f() local b = a; for x,v in pairs(upvalues()) do print(x,v) end end; f()
    a   2
    

    【讨论】:

    • 完美运行!非常感谢!
    • 为什么将pairs存储在(*temporary)中?
    • 很高兴,这是一个 Lua 实现的东西
    【解决方案2】:

    使用debug.getlocal

    【讨论】:

    • 它太短了,对于那些通过我提出的问题访问网络的人来说是有用的。不过还是谢谢!
    【解决方案3】:

    debug.getlocal:

    local foobar = 1
    
    local i = 0
    repeat
        local k, v = debug.getlocal(1, i)
        if k then
            print(k, v)
            i = i + 1
        end
    until nil == k
    

    输出:

    foobar  1
    i       2
    

    【讨论】:

    • 您是否运行了您粘贴的代码?我在 Ubuntu 上使用 Lua 5.1.4 运行它,它根本不打印任何东西。我将代码保存在一个文件中,并在控制台中使用lua test.lua 执行。我错过了什么吗?
    • 是的,我在 Ubuntu 10.04 上使用相同版本的 Lua 运行它。
    • 您是按原样将其放在文件中还是将其包装在函数调用中?
    • 我认为任何块都可以做到这一点,文件就是一个块,不是吗?无论如何,我只是将它包装在一个函数中也无济于事:(我在 Ubuntu 9.04 (Jaunty) 上。
    【解决方案4】:

    上面梅加登法官的循环版本的问题只是local i = 0。 它什么也不做,因为第一个索引为 '0' 的总是返回 nil。

    记住 Lua 索引默认以“1”开头,而不是像 C/C++ 那样的“0”。 当然,您可以将“0”用于具有自己类型的索引,但默认功能 期待默认的 '1' 作为第一个索引。

    只需将其更改为local i = 1,他的循环就可以正常工作了。

    【讨论】:

      【解决方案5】:

      您可以使用getfenv 获取本地环境。

      getfenv ([f]) 返回当前 函数使用的环境。 F 可以是 Lua 函数或数字 指定该堆栈中的函数 级别:级别 1 是函数调用 得到芬夫。如果给定的函数不是 一个 Lua 函数,或者如果 f 为 0,getfenv 返回全局环境。这 f 的默认值为 1。

      编辑:抱歉,我错了。

      我刚刚检查了 Lua 源代码。 debug.getlocal() 是获取局部变量的唯一途径。
      Lua 使用内部的Proto 结构,并且不允许我们访问它。
      (Proto 包含本地属性和父 Proto 引用。使用 getfenv 迭代函数的 Proto,
      我们还迭代继承的属性,而不是我们想要的)

      用户可以使用环境和set/getfenv 函数或使用元表来定义他们的Proto

      【讨论】:

      • 您的解决方案无效。以下不打印foobar: local foobar = 1; for k,v in pairs(getfenv()) do print(k, v) end 我错过了什么吗?
      • 我相信getfenv 只会显示具有给定范围/环境的全局变量。
      • @Judge,是的,但是我们可以将函数的 env 替换为其他的。正如我所发现的,当我们迭代一个 env 时,我们也迭代了继承的内部原型链。除非我们使用内置的debug.getlocal,否则我们无法真正获得本地声明。
      猜你喜欢
      • 2011-09-09
      • 1970-01-01
      • 2011-04-19
      • 1970-01-01
      • 2012-02-26
      • 2012-03-07
      • 2017-12-15
      • 2013-05-14
      • 1970-01-01
      相关资源
      最近更新 更多