Перечислить или перечислить все переменные в программе на [ваш любимый язык здесь] [закрыто]


80

На прошлой неделе друг спросил меня, как перечислить или перечислить все переменные в программе / функции / и т. Д. для целей отладки (по сути, получение снимка всего, чтобы вы могли видеть, какие переменные установлены, или установлены ли они вообще). Я немного огляделся и нашел относительно хороший способ для Python:

#! / usr / bin / python                                                                                                                                                                                                                           
foo1 = "Привет, мир"
foo2 = "бар"
foo3 = {"1": "а",
        "2": "b"}
foo4 = "1 + 1"

для имени в dir ():
    myvalue = eval (имя)
    напечатать имя, «есть», тип (имя), «и равно», myvalue

что выведет что-то вроде:

__builtins__ - это <тип 'str'> и равно <модуль '__builtin__' (встроенный)>
__doc__ имеет значение <type 'str'> и равно None
__file__ - это <тип 'str'> и равно ./foo.py
__name__ - это <тип 'str'> и равно __main__
foo1 - это <type 'str'> и равно Hello world
foo2 - это <type 'str'> и равно bar
foo3 - это <type 'str'> и равно {'1': 'a', '2': 'b'}
foo4 имеет значение <type 'str'> и равно 1 + 1

До сих пор я частично нашел способ в PHP (любезно предоставлен текст ссылки ), но он перечисляет только все переменные и их типы, а не содержимое:

<? php
// создаем несколько переменных
$ bar = 'foo';
$ foo = 'бар';
// создаем новый объект массива
$ arrayObj = новый объект ArrayObject (get_defined_vars ());
// цикл по объекту массива и эхо-переменным и значениям
for ($ iterator = $ arrayObj-> getIterator (); $ iterator-> valid (); $ iterator-> next ())
        {
        эхо $ итератор-> ключ (). '=>'. $ итератор-> текущий (). '<br />';
        }
?>

Итак, я задаю вам вопрос: как вы перечисляете все переменные и их содержимое на вашем любимом языке?


Редактировать VonC : Я предлагаю, что этот вопрос следует духу небольшого « вызова кода ».
Если вы не согласны, просто отредактируйте и удалите тег и ссылку.


4
В python я бы просто использовал locals / globals, а не dir / eval, который вы показываете выше. Смотри ниже.
Аарон Маенпаа,

В PHP это тоже можно сделать намного проще, см. Мой ответ.
Пим Ягер,

1
Я не согласен, мой план состоит в том, чтобы выбрать наиболее элегантное решение в целом и установить его как ответ и готово. Я полагаю, что если бы я задавал один из них для каждого отдельного вопроса, который был бы больше квалифицирован как «правильный» вопрос, но стоит отметить, что методы, используемые на разных языках, часто пересекаются с другими языками (т.е. используют отладчик и т. Д.).
Курт

1
отличный пост. Мне это нужно, чтобы получить список переменных, которые я определил в модуле. с добавленным тестом 'not name.startswith (' __ ')' (с использованием python) это творит чудеса для меня. Большое спасибо
ShadowFlame

2
Вздох. Не должно быть одновременно: 1) закрытого из-за того, что он слишком широк, потому что он на нескольких языках, и 2) как «дублирующего перенаправления» для вопросов на одном языке.
Charles Merriam

Ответы:


93

В python использование locals, которое возвращает словарь, содержащий все локальные привязки, таким образом избегая eval:

>>> foo1 = "Hello world"
>>> foo2 = "bar"
>>> foo3 = {"1":"a",
...         "2":"b"}
>>> foo4 = "1+1"

>>> import pprint
>>> pprint.pprint(locals())
{'__builtins__': <module '__builtin__' (built-in)>,
 '__doc__': None,
 '__name__': '__main__',
 'foo1': 'Hello world',
 'foo2': 'bar',
 'foo3': {'1': 'a', '2': 'b'},
 'foo4': '1+1',
 'pprint': <module 'pprint' from '/usr/lib/python2.5/pprint.pyc'>}

11

Вот как это будет выглядеть в Ruby :

#!/usr/bin/env ruby

foo1 = 'Hello world'
foo2 = 'bar'
foo3 = { '1' => 'a', '2' => 'b' }
foo4 = '1+1'

b = binding
local_variables.each do |var|
  puts "#{var} is #{var.class} and is equal to #{b.local_variable_get(var).inspect}"
end

который выведет

foo1 - это String и равно "Hello world"
foo2 - это String и равно bar
foo3 - это String и равно {"1" => "a", "2" => "b"}
foo4 - это String и равно "1 + 1"

Однако разве вы не имели в виду выводить тип объекта, на который ссылается переменная, вместо типа, используемого для представления идентификатора переменной? IOW, тип foo3должен быть Hash(или dict) вместо String, верно? В этом случае код будет

#!/usr/bin/env ruby

foo1 = 'Hello world'
foo2 = 'bar'
foo3 = { '1' => 'a', '2' => 'b' }
foo4 = '1+1'

b = binding
local_variables.each do |var|
  val = b.local_variable_get(var)
  puts "#{var} is #{val.class} and is equal to #{val.inspect}"
end

и результат

foo1 - это String и равно "Hello world"
foo2 - это String и равно bar
foo3 - это Hash и равно {"1" => "a", "2" => "b"}
foo4 - это String и равно "1 + 1"

1
вам также, вероятно, следует включить: instance_variables global_variables константы class_variables
Rado,

По крайней мере, в Ruby 2.2 я должен был использовать, например,instance_variable_get(instance_variables[0])
jberryman

10

IPython:

whos

Вы также можете порекомендовать своему другу Spyder, который показывает эти переменные почти так же, как Matlab, и предоставляет графический интерфейс для построчной отладки.


9

В php вы можете сделать это:

$defined = get_defined_vars(); 
foreach($defined as $varName => $varValue){
 echo "$varName is of type ".gettype($varValue)." and has value $varValue <br>";
}

3
+1 Приятно, эта функция непонятна, но это один из самых маленьких примеров, и некоторые до сих пор говорят, что PHP - отстой. =)
Аликс Аксель

9

В Lua фундаментальной структурой данных является таблица, и даже глобальная среда _G - это таблица. Итак, простое перечисление поможет.

for k,v in pairs(_G) do
  print(k..' is '..type(v)..' and is equal to '..tostring(v))
end


6

Полностью рекурсивный однострочник PHP:

print_r(get_defined_vars());

4

Во-первых, я бы просто использовал отладчик; например, в Visual Studio есть окна «Локальные» и «Наблюдение», в которых будут отображаться все переменные и т. Д., Которые вы хотите, полностью расширяемые до любого уровня.

В C # вы не можете легко получить доступ к переменным метода (и многие из них могут быть удалены компилятором), но вы можете получить доступ к полям и т. Д. Через отражение:

static class Program { // formatted for minimal vertical space
    static object foo1 = "Hello world", foo2 = "bar",
                  foo3 = new[] { 1, 2, 3 }, foo4;
    static void Main() {
        foreach (var field in typeof(Program).GetFields(
                BindingFlags.Static | BindingFlags.NonPublic)) {
            var val = field.GetValue(null);
            if (val == null) {
                Console.WriteLine("{0} is null", field.Name);
            } else {
                Console.WriteLine("{0} ({1}) = {2}",
                    field.Name, val.GetType().Name, val);
            }
        }
    }
}

4

Perl. Не обрабатывает myлокальные переменные и не отфильтровывает некоторые бесполезные ссылки, но все в области пакета можно увидеть.

my %env = %{__PACKAGE__ . '::'};
while (($a, $b) = each %env) {
    print "\$$a = $$b\n";
    print "\@$a = (@$b)\n";
    print "%$a = (@{[%$b]})\n";
    print "*$a = $b\n";
}



2

В java проблема будет похожа на C #, только в более подробном режиме (я знаю, я ЗНАЮ ;) Java многословна ... вы уже ясно дали понять;) )

Вы можете получить доступ к полям объекта через Refection, но вы не можете легко получить доступ к локальным переменным метода. Таким образом, следующее предназначено не для кода статического анализа, а только для отладки во время выполнения.

package test;

import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;

/**
 * 
 * @author <a href="https://stackoverflow.com/users/6309/vonc">VonC</a>
 */
public class DisplayVars
{

    private static int field1 = 1;
    private static String field2 = "~2~";
    private boolean isField = false;

    /**
     * @param args
     */
    public static void main(final String[] args)
    {
        final Field[] someFields = DisplayVars.class.getDeclaredFields();
        try
        {
            displayFields(someFields);
        } catch (IllegalAccessException e)
        {
            e.printStackTrace();
        }
    }

    /**
     * @param someFields
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     */
    @SuppressWarnings("unchecked")
    public static void displayFields(final Field[] someFields)
            throws IllegalAccessException
    {
        DisplayVars anObject = new DisplayVars();
        Object res = null;
        for (int ifields = 0; ifields < someFields.length; ifields++)
        {
            final Field aField = someFields[ifields];
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run()
                {
                    aField.setAccessible(true);
                    return null; // nothing to return
                }
            });
            res = aField.get(anObject);
            if (res != null)
            {
                System.out.println(aField.getName() + ": " + res.toString());
            } else
            {
                System.out.println(aField.getName() + ": null");
            }
        }
    }
}

Или вы можете использовать Apache Commons Beanutils.
Аарон Дигулла,

Многословна не Java, а ваш код. Для начала бессмысленные комментарии плюс полностью устаревшие операции, например, вся работа с ними AccessControllerне нужна в автономном приложении (ну, в setAccessibleлюбом ifслучае, не требуется для доступа к вашим собственным полям) или утверждение, чтобы различать два случая, которые могут быть обработаны таким же образом при удалении устаревшего toString()вызова: System.out.println(aField.getName() + ": " + res);работает независимо от того, resесть он nullили нет. И нет необходимости распространять код на несколько методов…
Хольгер,

1

В REBOL все переменные находятся в контексте типа object!. Есть глобальный контекст, и каждая функция имеет свой собственный неявный локальный контекст. Вы можете создавать новые контексты явно, создавая новый object!(или используяcontext функцию). Это отличается от традиционных языков, потому что переменные (называемые «словами» в REBOL) несут ссылку на свой контекст вокруг себя, даже когда они покинули «область действия», в которой они были определены.

Итак, суть в том, что, учитывая контекст, мы можем перечислить переменные, которые он определяет. Воспользуемся функцией Ладислава Мечира context-words?.

context-words?: func [ ctx [object!] ] [ bind first ctx ctx ]

Теперь мы можем перечислить все слова, определенные в глобальном контексте. (Их очень много .)

probe context-words? system/words

Мы также можем написать функцию, которая затем перечислит переменные, которые она определяет.

enumerable: func [a b c /local x y z] [
  probe context-words? bind? 'a
]

Что мы Насколько я знаю, в REBOL не можем пройти вверх по контекстному дереву, хотя интерпретатор, кажется, может делать это отлично, когда решает, как связать слова с их контекстами. Я думаю, это связано с тем, что контекстное дерево (т.е. область видимости) может иметь одну «форму» во время связывания слова, но совсем другую во время его оценки.


1

Быстрое и грязное решение JavaScript, если у вас установлен FireBug (или другой браузер с console.log). Если вы этого не сделаете, вам придется изменить console.log на document.write и запустить его как встроенный скрипт в конце вашего. Измените MAX_DEPTH на желаемое количество уровней рекурсии (будьте осторожны!).

(function() {
    var MAX_DEPTH = 0;
    function printObj(name, o, depth) {
        console.log(name + " type: '"+typeof o+"' value: " + o);

        if(typeof o == "function" || depth >= MAX_DEPTH) return;
        for(var c in o) {
            printObj(name+"."+c, o[c], depth+1);
        }
    }
    for(var o in window) {
        printObj(o, window[o], 0);
    }
})();

0

Общий Лисп:

(do-all-symbols (x) (print x))

Чтобы также показать все связанные значения:

(do-all-symbols (x) (print x) (when (boundp x) (print (symbol-value x))))

Это длинный список, и он не особо полезен. Я бы действительно использовал встроенный отладчик.


0

Вот идея для oo-languages.

Сначала вам нужно что-то вроде toString () в Java для печати значимого содержимого. Во-вторых, вы должны ограничиться одной иерархией объектов. В конструкторе корневого объекта (например, Any в Eiffel) вы регистрируете экземпляр при создании в каком-то глобальном списке. Во время уничтожения вы отменяете регистрацию (обязательно используйте некоторую структуру данных, которая позволяет быстро вставлять / искать / удалять). В любой момент во время выполнения программы вы можете пройти через эту структуру данных и распечатать все зарегистрированные в ней объекты.

Благодаря своей структуре Эйфель может быть очень хорош для этой цели. Другие языки имеют проблемы с объектами, которые не определены пользователем (например, jdk-классы). В Java можно было бы создать свой собственный объектный класс, используя некоторый открытый исходный код jdk.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.