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.


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

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”

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.


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

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

6

Grzmotnąć:

set

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


3
Porównaj z, envaby znaleźć wartości, które nie zostały wyeksportowane.
Nitrodist


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

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


4

W języku R.

ls()

i usunąć wszystkie obiekty z pamięci roboczej

rm(list=ls(all=TRUE))

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

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.


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);
    }
})();

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.


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.