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

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

#!/usr/bin/python                                                                                                                                                                                                                           
foo1 = "Hello world"
foo2 = "bar"
foo3 = {"1":"a",
        "2":"b"}
foo4 = "1+1"

for name in dir():
    myvalue = eval(name)
    print name, "is", type(name), "and is equal to ", myvalue

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

__builtins__ is <type 'str'> and is equal to  <module '__builtin__' (built-in)>
__doc__ is <type 'str'> and is equal to  None
__file__ is <type 'str'> and is equal to  ./foo.py
__name__ is <type 'str'> and is equal to  __main__
foo1 is <type 'str'> and is equal to  Hello world
foo2 is <type 'str'> and is equal to  bar
foo3 is <type 'str'> and is equal to  {'1': 'a', '2': 'b'}
foo4 is <type 'str'> and is equal to  1+1

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

<?php
// create a few variables
$bar = 'foo';
$foo ='bar';
// create a new array object
$arrayObj = new ArrayObject(get_defined_vars());
// loop over the array object and echo variables and values
for($iterator = $arrayObj->getIterator(); $iterator->valid(); $iterator->next())
        {
        echo $iterator->key() . ' => ' . $iterator->current() . '<br />';
        }
?>

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


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

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

Aaron Maenpaa 10.01.2009 14:28

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

Pim Jager 10.01.2009 21:57

Это хитрость вопроса, потому что он не спрашивает о конкретной проблеме, а говорит: «Давайте посмотрим, что вы можете сделать на вашем языке?». Это дискуссионный вопрос, потому что нет однозначного правильного ответа. Поэтому его, вероятно, следует удалить, но хотя бы пометить вики сообщества. Это больше сообщение на форуме.

Mark Rogers 23.05.2009 23:36

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

Kurt 24.05.2009 23:27

@MarkRogers, я думал о том же самом. Ответы действительно полезны, но вопрос не так квалифицирован. Я согласен, что он должен идти CW.

Tyler Crompton 21.02.2012 09:46

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

ShadowFlame 28.08.2012 10:08

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

Charles Merriam 22.06.2018 01:54

@CharlesMerriam Я согласен, использование этого в качестве цели обмана для конкретных языковых вопросов в основном означает, что «каждый отдельный вопрос о том, как получить список переменных, должен быть закрыт».

jrh 21.10.2018 17:39
Библиотека для работы с мороженым
Библиотека для работы с мороженым
Лично я попрощался с операторами print() в python. Без шуток.
80
8
56 490
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

Во-первых, я бы просто использовал отладчик ;-p В 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);
            }
        }
    }
}

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

#!/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 is String and is equal to "Hello world"
foo2 is String and is equal to "bar"
foo3 is String and is equal to {"1"=>"a", "2"=>"b"}
foo4 is String and is equal to "1+1"

Однако разве вы не хотели вывести тип объекта, на который ссылается переменная, вместо типа, используемого для представления идентификатора переменной? Да, тип 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 is String and is equal to "Hello world"
foo2 is String and is equal to "bar"
foo3 is Hash and is equal to {"1"=>"a", "2"=>"b"}
foo4 is String and is equal to "1+1"

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

Rado 01.07.2010 02:13

По крайней мере, в Ruby 2.2 мне пришлось использовать, например, instance_variable_get(instance_variables[0])

jberryman 12.01.2016 00:38
Ответ принят как подходящий

В 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'>}

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

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

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

Alix Axel 22.05.2009 05:23

В 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.

Aaron Digulla 25.05.2009 13:14

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

Holger 26.01.2016 20:56

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";
}

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

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

Matlab:

who

Общий Лисп:

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

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

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

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

Вот идея для oo-языков.

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

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

Баш:

set

Отказ от ответственности: не мой любимый язык!

Сравните с env, чтобы узнать, что значения не экспортированы.

Nitrodist 16.03.2011 23:18

В 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 поднимается вверх по контекстному дереву, хотя интерпретатор, кажется, может делать это отлично, когда решает, как связать слова с их контекстами. Я думаю, это связано с тем, что контекстное дерево (т.е. область видимости) может иметь одну «форму» во время связывания слова, но совсем другую во время его оценки.

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

print_r(get_defined_vars());

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

(function() {
    var MAX_DEPTH = 0;
    function printObj(name, o, depth) {
        console.info(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);
    }
})();

На языке R

ls()

и удалить все объекты из рабочей памяти

rm(list=ls(all=TRUE))

IPython:

whos

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

Другие вопросы по теме