Перелічіть або перелічіть усі змінні в програмі [улюбленої мови тут] [закрито]


80

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

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

для імені в папці ():
    myvalue = eval (ім'я)
    друкувати ім'я, "є", тип (ім'я), "і дорівнює", myvalue

який виведе щось на зразок:

__builtins__ має <тип 'str'> і дорівнює <модулю '__builtin__' (вбудований)>
__doc__ має <тип 'str'> і дорівнює None
__file__ має <тип 'str'> і дорівнює ./foo.py
__name__ має <тип 'str'> і дорівнює __main__
foo1 має <тип 'str'> і дорівнює Hello world
foo2 має <тип 'str'> і дорівнює бар
foo3 має <тип 'str'> і дорівнює {'1': 'a', '2': 'b'}
foo4 має <тип 'str'> і дорівнює 1 + 1

Я поки що знайшов частковий спосіб у PHP (люб'язно надавши текст посилання ), але він перераховує лише всі змінні та їх типи, а не вміст:

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

Тож я вам це сказав: як ви перелічуєте всі змінні та їх вміст улюбленою мовою?


Редагування VonC : Я вважаю, що це питання відповідає духу невеликого " виклику коду ".
Якщо ви не згодні, просто відредагуйте та видаліть тег та посилання.


4
У python я б просто використовував local / globals, а не dir / eval, який ви показуєте вище. Дивись нижче.
Аарон Маенпаа

У PHP це також можна зробити набагато простіше, див. Мою відповідь.
Пім Ягер

1
Я не згоден, мій план полягає в тому, щоб вибрати найбільш елегантне рішення в цілому і встановити це як відповідь і попереднє. Я гадаю, якщо б я задав одне з них для кожного окремого питання, яке б більше кваліфікувалось як "належне" питання, але варто зазначити, що методи, що використовуються в різних мовах, часто збігаються з іншими мовами (тобто використовують налагоджувач / тощо).
Курт,

1
чудовий пост. Мені це потрібно було, щоб отримати список змінних, які я визначив у модулі. з доданим тестом 'not name.startswith (' __ ')' (за допомогою python) це робить для мене чудеса. Велике спасибі
ShadowFlame

2
Зітхайте. Не слід обидва бути 1) закритим через занадто широку, оскільки він складається з декількох мов, і 2) будучи "повторним переспрямуванням" для питань однієї мови.
Чарльз Мерріам,

Відповіді:


93

У python, використовуючи локали, які повертають словник, що містить усі локальні прив'язки, таким чином, уникаючи 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 - це рядок і дорівнює "Привіт світ"
foo2 - це рядок і дорівнює "бар"
foo3 є рядком і дорівнює {"1" => "a", "2" => "b"}
foo4 є рядком і дорівнює "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 - це рядок і дорівнює "Привіт світ"
foo2 - це рядок і дорівнює "бар"
foo3 - це хеш і дорівнює {"1" => "a", "2" => "b"}
foo4 є рядком і дорівнює "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

По-перше, я просто скористався налагоджувачем; - 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);
            }
        }
    }
}

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 і запустити at як вбудований скрипт в кінці вашого. Змініть 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

Загальний Lisp:

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

Щоб також показати всі пов'язані значення:

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

Це довгий список і не особливо корисний. Я б справді використовував вбудований налагоджувач.


0

Ось ідея для oo-мов.

Спочатку вам потрібно щось на зразок toString () на Java, щоб надрукувати змістовний вміст. Друге - вам доведеться обмежитися одним об’єктом-ієрархією. У конструкторі кореневого об'єкта (як Any в Ейфелі) ви реєструєте екземпляр при створенні в якомусь глобальному списку. Під час знищення ви скасовуєте реєстрацію (обов’язково використовуйте певну структуру даних, яка дозволяє швидко вставляти / шукати / видаляти). Будь-коли під час виконання програми ви можете пройти цю структуру даних і роздрукувати всі зареєстровані там об’єкти.

Завдяки своїй структурі, Ейфель може бути дуже хорошим для цієї мети. Інші мови мають проблеми з об’єктами, які не визначаються користувачем (наприклад, jdk-класи). У Java може бути можливо створити власний Object-клас, використовуючи який-небудь jdk з відкритим кодом.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.