views:

253

answers:

4

I know how to print "all" global variables using the following code

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

So my question is how to do that for all variables that are accessible from the currently executing function, something that can do what locals() does for Python.

A: 

You can use getfenv to get a local environment.

getfenv ([f]) Returns the current environment in use by the function. f can be a Lua function or a number that specifies the function at that stack level: Level 1 is the function calling getfenv. If the given function is not a Lua function, or if f is 0, getfenv returns the global environment. The default for f is 1.

Edit: sorry, I was wrong.

I just checked Lua source code. debug.getlocal() is the only way to get the local variables.
Lua uses an internal Proto structure and doesn't give us access to that.
(Proto holds local properties plus a parent Proto reference. Iterating function's Proto, by using getfenv,
we also iterate inherited properties, not what we wanted)

Users can define their Proto s either with environments and the set/getfenv functions or by using metatables.

Nick D
Your solution did not work. The following does not print `foobar`: local foobar = 1; for k,v in pairs(getfenv()) do print(k, v) endAm I missing something?
Edu Felipe
I believe `getfenv` will only show globals withing the given scope/environment.
Judge Maygarden
@Judge, yes, but we can replace function's env with some other. As I discovered, when we iterate over an env we also iterate over the inherited chain of internal prototypes. We cannot really get local declarations unless we use the built-in `debug.getlocal`.
Nick D
+2  A: 

Use debug.getlocal.

lhf
It's too short to be useful for someone hitting the web with the question I asked. But thanks anyway!
Edu Felipe
A: 

See 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

Output:

foobar  1
i       2
Judge Maygarden
Did you run the code you pasted? I'm running it using Lua 5.1.4 on Ubuntu and it does not print anything at all. I saved the code on a file and executed in the console with `lua test.lua`. Am I missing something?
Edu Felipe
Yes, I ran it on Ubuntu 10.04 with the same version of Lua.
Judge Maygarden
Did you place it in a file as is or wrap it in a function call?
Judge Maygarden
I thought any chunk would do it, and a file is a chunk, isn't it? Anyway, I just wrapped it in a function to no avail either :(I'm on Ubuntu 9.04 (Jaunty).
Edu Felipe
+4  A: 

Here is an implementation of a locals() function. It will return a table of locals from the calling scope:

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

Notice that in the lua REPL, each line is a separate chunk with separate locals. Also, internal variables are returned (names start with '(' if you want to remove them):

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

Thanks for the accept. You have unlocked the last piece of the puzzle! ;-)

Upvalues are local variables from outer scopes, that are used in the current function. They are neither in _G nor in 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

Example (notice you have to use a for it to show up):

> local a= 2; function f() local b = a; for x,v in pairs(upvalues()) do print(x,v) end end; f()
a   2
kaizer.se
Works perfectly! Thanks so much!
Edu Felipe