Wylicz lub wyświetl wszystkie zmienne w programie [tutaj twój ulubiony język] [zamknięte]

80

Znajomy zapytał mnie w zeszłym tygodniu, jak wyliczyć lub wyświetlić wszystkie zmienne w programie / funkcji / itp. do celów debugowania (zasadniczo uzyskania migawki wszystkiego, abyś mógł zobaczyć, jakie zmienne są ustawione lub czy w ogóle są ustawione). Rozejrzałem się trochę i znalazłem stosunkowo dobry sposób na Pythona:

#! / usr / bin / python                                                                                                                                                                                                                           
foo1 = "Witaj świecie"
foo2 = "bar"
foo3 = {"1": "a",
        "2": "b"}
foo4 = „1 + 1”

dla nazwy w dir ():
    myvalue = eval (nazwa)
    wypisz nazwę, „jest”, wpisz (nazwa), „i jest równe”, moja wartość

który wyświetli coś takiego:

__builtins__ jest <typ 'str'> i jest równe <moduł '__builtin__' (wbudowany)>
__doc__ to <type 'str'> i jest równe None
__file__ to <typ „str”> i jest równe ./foo.py
__name__ to <type 'str'> i jest równe __main__
foo1 to <type 'str'> i jest równe Hello world
foo2 jest <typ 'str'> i jest równe bar
foo3 jest <type 'str'> i jest równe {'1': 'a', '2': 'b'}
foo4 jest <typ 'str'> i jest równe 1 + 1

Do tej pory znalazłem częściowy sposób w PHP (dzięki uprzejmości tekstu linku ), ale zawiera on tylko wszystkie zmienne i ich typy, a nie zawartość:

<? php
// utwórz kilka zmiennych
$ bar = 'foo';
$ foo = 'bar';
// utwórz nowy obiekt tablicy
$ arrayObj = new ArrayObject (get_defined_vars ());
// pętla po obiekcie tablicy i echo zmiennych i wartości
for ($ iterator = $ arrayObj-> getIterator (); $ iterator-> valid (); $ iterator-> next ())
        {
        echo $ iterator-> key (). '=>'. $ iterator-> current (). '<br />';
        }
?>

Powiedziałem ci więc: jak wypisujesz wszystkie zmienne i ich zawartość w swoim ulubionym języku?


Edit by VonC : Proponuję, aby to pytanie było zgodne z duchem małego „ wyzwania kodu ”.
Jeśli nie wyrażasz zgody, po prostu edytuj i usuń tag oraz link.

Kurt
źródło
4
W Pythonie użyłbym tylko locals / globals, a nie dir / eval, który pokazałeś powyżej. Zobacz poniżej.
Aaron Maenpaa
W PHP można to zrobić znacznie łatwiej, zobacz moją odpowiedź.
Pim Jager
1
Nie zgadzam się, mój plan jest taki, aby ogólnie wybrać najbardziej eleganckie rozwiązanie i ustawić je jako odpowiedź i presto. Przypuszczam, że gdybym zadał jedno z tych pytań dla każdego indywidualnego pytania, które kwalifikowałoby się bardziej jako „właściwe” pytanie, ale warto zauważyć, że metody używane w różnych językach często pokrywają się z innymi językami (np. Użyj debuggera / itp.).
Kurt
1
wspaniały post. Potrzebowałem tego, aby uzyskać listę zmiennych, które zdefiniowałem w module. z dodanym testem 'not name.startswith (' __ ')' (używając Pythona) robi to dla mnie cuda.
Wielkie
2
Westchnienie. Nie powinno być jednocześnie 1) zamkniętym ze względu na to, że jest zbyt szerokie, ponieważ zawiera wiele języków, oraz 2) będąc „powtórzonym przekierowaniem” w przypadku pytań dotyczących jednego języka.
Charles Merriam

Odpowiedzi:

93

W Pythonie, używając lokalnych, które zwracają słownik zawierający wszystkie lokalne powiązania, unikając w ten sposób 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'>}
Aaron Maenpaa
źródło
11

Tak by to wyglądało w Rubim :

#!/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

które wyjdą

foo1 to String i jest równe „Hello world”
foo2 to String i jest równe „bar”
foo3 jest ciągiem i jest równe {"1" => "a", "2" => "b"}
foo4 to String i jest równe „1 + 1”

Jednak czy nie chodziło Ci o wyprowadzenie typu obiektu, do którego odwołuje się zmienna, zamiast typu używanego do reprezentowania identyfikatora zmiennej? IOW, typ foo3powinien być Hash(lub dict) zamiast String, prawda? W takim przypadku kod byłby

#!/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

a wynik jest

foo1 to String i jest równe „Hello world”
foo2 to String i jest równe „bar”
foo3 to Hash i jest równe {"1" => "a", "2" => "b"}
foo4 to String i jest równe „1 + 1”
Jörg W Mittag
źródło
1
prawdopodobnie powinieneś również dołączyć: instance_variables global_variables class_variables constants
Rado
Przynajmniej w ruby ​​2.2 musiałem użyć np.instance_variable_get(instance_variables[0])
jberryman
10

IPython:

whos

Możesz również polecić Spyder swojemu przyjacielowi, który pokazuje te zmienne prawie tak, jak robi to Matlab i zapewnia GUI do debugowania linia po linii.

Eder Santana
źródło
9

W php możesz to zrobić:

$defined = get_defined_vars(); 
foreach($defined as $varName => $varValue){
 echo "$varName is of type ".gettype($varValue)." and has value $varValue <br>";
}
Pim Jager
źródło
3
+1 Fajnie, ta funkcja jest trochę niejasna, ale jest to jeden z najmniejszych przykładów tutaj, a niektórzy nadal twierdzą, że PHP jest do bani. =)
Alix Axel
9

W Lua podstawową strukturą danych jest tabela, a nawet globalne środowisko _G jest tabelą. Tak więc proste wyliczenie załatwi sprawę.

for k,v in pairs(_G) do
  print(k..' is '..type(v)..' and is equal to '..tostring(v))
end
Nick Dandoulakis
źródło
6

Grzmotnąć:

set

Zastrzeżenie: To nie jest mój ulubiony język!

za dużo php
źródło
3
Porównaj z, envaby znaleźć wartości, które nie zostały wyeksportowane.
Nitrodist
6

W pełni rekursywny, jednowierszowy PHP:

print_r(get_defined_vars());
LapTop006
źródło
4

Po pierwsze, użyłbym po prostu debugera ;-p Visual Studio, na przykład, ma okna „Lokalne” i „Obserwuj”, które pokażą wszystkie potrzebne zmienne itp., W pełni rozszerzalne do dowolnego poziomu.

W C # nie można bardzo łatwo dostać się do zmiennych metod (i wiele z nich może zostać usuniętych przez kompilator) - ale można uzyskać dostęp do pól itp. Poprzez odbicie:

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);
            }
        }
    }
}
Marc Gravell
źródło
4

Perl. Nie obsługuje mylokalnych i nie odfiltrowuje niektórych bezużytecznych odniesień, ale można zobaczyć wszystko w zakresie pakietu.

my %env = %{__PACKAGE__ . '::'};
while (($a, $b) = each %env) {
    print "\$$a = $$b\n";
    print "\@$a = (@$b)\n";
    print "%$a = (@{[%$b]})\n";
    print "*$a = $b\n";
}
ephemient
źródło
4

Matlab:

who
Dario
źródło
4

W języku R.

ls()

i usunąć wszystkie obiekty z pamięci roboczej

rm(list=ls(all=TRUE))
Tiago Zortea
źródło
2

W javie problem byłby podobny do C #, tylko w bardziej szczegółowym trybie (wiem, WIEM ;) Java jest gadatliwa ... już to wyjaśniłeś;) )

Możesz uzyskać dostęp do pól obiektu poprzez Refection, ale możesz nie mieć łatwego dostępu do metod zmiennych lokalnych. Dlatego poniższe informacje nie dotyczą kodu analizy statycznej, ale tylko debugowania w czasie wykonywania.

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");
            }
        }
    }
}
VonC
źródło
Lub możesz użyć Apache Commons Beanutils.
Aaron Digulla
To nie Java jest gadatliwa, ale twój kod. Na początek bezsensowne komentarze plus całkowicie przestarzałe operacje, np. Całe załatwienie AccessControllerjest zbędne w samodzielnej aplikacji (no cóż, i tak setAccessiblejest zbędne, aby mieć dostęp do własnych pól) lub ifstwierdzenie rozróżnienia między dwoma przypadkami, które można załatwić tak samo jak przy usuwaniu przestarzałego toString()wywołania: System.out.println(aField.getName() + ": " + res);działa niezależnie od tego, czy resjest, nullczy nie. Nie ma też potrzeby dzielenia kodu na wiele metod…
Holger
1

W REBOL wszystkie zmienne znajdują się w kontekście typu object!. Istnieje kontekst globalny, a każda funkcja ma swój własny domyślny kontekst lokalny. Możesz jawnie tworzyć nowe konteksty, tworząc nowy object!(lub używająccontext funkcji). Różni się to od tradycyjnych języków, ponieważ zmienne (zwane w języku REBOL „słowami”) niosą ze sobą odniesienie do otaczającego ich kontekstu, nawet jeśli opuściły „zakres”, w którym zostały zdefiniowane.

Zatem najważniejsze jest to, że biorąc pod uwagę kontekst, możemy wyświetlić listę zmiennych, które definiuje. Skorzystamy z context-words?funkcji Ladislava Mecira .

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

Teraz możemy wymienić wszystkie słowa zdefiniowane w kontekście globalnym. (Jest ich dużo .)

probe context-words? system/words

Możemy również napisać funkcję, która następnie wyświetli listę zmiennych, które definiuje.

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

To, czego nie możemy zrobić w REBOL-u, o ile wiem, to chodzić po drzewie kontekstu, chociaż tłumacz wydaje się być w stanie zrobić to doskonale, kiedy decyduje, jak powiązać słowa z ich kontekstami. Myślę, że dzieje się tak dlatego, że drzewo kontekstu (tj. Zasięg) może mieć jeden „kształt” w momencie wiązania słowa, a zupełnie inny w momencie oceny.

Gregory Higley
źródło
1

Szybkie i brudne rozwiązanie JavaScript, jeśli masz zainstalowany FireBug (lub inną przeglądarkę z console.log). Jeśli tego nie zrobisz, będziesz musiał zmienić console.log na document.write i uruchomić go jako wbudowany skrypt na końcu twojego. Zmień MAX_DEPTH na ile chcesz poziomów rekurencji (uważaj!).

(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);
    }
})();
Gregers
źródło
0

Wspólny Lisp:

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

Aby również pokazać wszystkie wartości powiązane:

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

To jest długa lista i niezbyt przydatna. Naprawdę użyłbym zintegrowanego debuggera.

Svante
źródło
0

Oto pomysł na języki oo.

Najpierw potrzebujesz czegoś takiego jak toString () w Javie, aby wydrukować znaczącą zawartość. Po drugie - musisz ograniczyć się do jednej hierarchii obiektów. W konstruktorze obiektu głównego (jak Any w Eiffel) rejestrujesz instancję podczas tworzenia na jakiejś globalnej liście. Podczas niszczenia wyrejestrowujesz się (pamiętaj, aby użyć jakiejś struktury danych, która umożliwia szybkie wstawianie / wyszukiwanie / usuwanie). W dowolnym momencie podczas wykonywania programu możesz przejść przez tę strukturę danych i wydrukować wszystkie zarejestrowane tam obiekty.

Ze względu na swoją konstrukcję, Eiffel może być bardzo dobry do tego celu. Inne języki mają problemy z obiektami, które nie są zdefiniowane przez użytkownika (np. Klasy jdk). W Javie może być możliwe stworzenie własnej klasy obiektów przy użyciu jdk typu open source.

Tobias Langner
źródło