Распечатать все локальные переменные, доступные для текущей области в Lua

Я знаю, как печатать «все» глобальные переменные, используя следующий код

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

Итак, мой вопрос заключается в том, как сделать это для всех переменных, доступных из текущей выполняемой функции, что-то, что может делать то, что locals() делает для Python.


person Edu Felipe    schedule 14.05.2010    source источник


Ответы (5)


Вот реализация функции 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

Пример (обратите внимание, что вы должны использовать для его отображения):

> local a= 2; function f() local b = a; for x,v in pairs(upvalues()) do print(x,v) end end; f()
a   2
person u0b34a0f6ae    schedule 14.05.2010
comment
Работает отлично! Большое спасибо! - person Edu Felipe; 14.05.2010
comment
Почему он хранит pairs в (*temporary)? - person happy_marmoset; 24.09.2013
comment
счастлив, это реализация Lua - person u0b34a0f6ae; 25.09.2013

Используйте 1_.

person lhf    schedule 14.05.2010
comment
Он слишком короткий, чтобы быть полезным для кого-то, кто попал в Интернет с вопросом, который я задал. Но все равно спасибо! - person Edu Felipe; 14.05.2010

См. 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
person Judge Maygarden    schedule 14.05.2010
comment
Вы запустили код, который вы вставили? Я запускаю его с помощью Lua 5.1.4 в Ubuntu, и он вообще ничего не печатает. Я сохранил код в файле и выполнил его в консоли с помощью lua test.lua. Я что-то упускаю? - person Edu Felipe; 14.05.2010
comment
Да, я запускал его на Ubuntu 10.04 с той же версией Lua. - person Judge Maygarden; 14.05.2010
comment
Вы поместили его в файл как есть или обернули вызовом функции? - person Judge Maygarden; 14.05.2010
comment
Я думал, что это сделает любой фрагмент, а файл — это фрагмент, не так ли? В любом случае, я просто завернул его в функцию, но безрезультатно :( Я на Ubuntu 9.04 (Jaunty). - person Edu Felipe; 14.05.2010

Проблема с версией петли судьи Мэйгардена выше просто local i = 0. Это ничего не делает, потому что первый индексированный с «0» всегда будет возвращать ноль.

Помните, что индексы Lua по умолчанию начинаются с «1», а не с «0», как в C/C++. Конечно, вы можете использовать «0» для индекса с вашими собственными типами, но функции по умолчанию ожидают значение по умолчанию «1» в качестве первого индекса.

Просто измените его на local i = 1, и его цикл будет работать нормально.

person Sirmabus    schedule 25.06.2012

Вы можете использовать getfenv, чтобы получить локальную среду.

getfenv ([f]) Возвращает текущую среду, используемую функцией. f может быть функцией Lua или числом, указывающим функцию на этом уровне стека: Уровень 1 — это функция, вызывающая getfenv. Если данная функция не является функцией Lua или если f равно 0, getfenv возвращает глобальную среду. Значение по умолчанию для f равно 1.

Редактировать: извините, я ошибся.

Я только что проверил исходный код Lua. debug.getlocal() — единственный способ получить локальные переменные.
Lua использует внутренний Proto структура и не дает нам доступа к ней.
(Proto содержит локальные свойства плюс ссылку на родительский Proto. Итерируя Proto функции, используя getfenv,
мы также итерируем унаследованные свойства, а не то, что хотели)

Пользователи могут определять свои Proto либо с помощью сред и функций set/getfenv, либо с помощью метатаблиц.

person Nick Dandoulakis    schedule 14.05.2010
comment
Ваше решение не сработало. Следующее не печатает foobar: local foobar = 1; для k,v в парах(getfenv()) do print(k, v) end Я что-то упустил? - person Edu Felipe; 14.05.2010
comment
Я считаю, что getfenv будет показывать только глобальные переменные в заданной области/среде. - person Judge Maygarden; 14.05.2010
comment
@ Судья, да, но мы можем заменить env функции на что-то другое. Как я обнаружил, когда мы перебираем env, мы также перебираем унаследованную цепочку внутренних прототипов. Мы не можем получить локальные объявления, если не используем встроенный debug.getlocal. - person Nick Dandoulakis; 14.05.2010