Enumera o elenca tutte le variabili in un programma della [tua lingua preferita qui] [chiuso]

StackOverflow https://stackoverflow.com/questions/430811

Domanda

La settimana scorsa un amico mi ha chiesto come elencare o elencare tutte le variabili all'interno di un programma / funzione / ecc. ai fini del debug (essenzialmente ottenere un'istantanea di tutto in modo da poter vedere su quali variabili sono impostate o se sono impostate affatto). Mi sono guardato un po 'in giro e ho trovato un modo relativamente buono per 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

che produrrà qualcosa del tipo:

__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

Finora ho trovato un modo parziale in PHP (per gentile concessione di testo del link ) ma elenca solo tutte le variabili e i loro tipi, non i contenuti:

<?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 />';
        }
?>

Quindi te lo dico io: come elenchi tutte le variabili e i loro contenuti nella tua lingua preferita?


Modifica di VonC : propongo che questa domanda segua lo spirito di un po '" code-challenge " ;.
Se non sei d'accordo, modifica e rimuovi il tag e il link.

È stato utile?

Soluzione

In python, usare la gente del posto che restituisce un dizionario contenente tutti i binding locali, evitando quindi l'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'>}

Altri suggerimenti

Ecco come sarebbe in 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

che produrrà

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"

Tuttavia, non intendevi produrre il tipo di oggetto a cui fa riferimento la variabile anziché il tipo utilizzato per rappresentare l'identificatore della variabile? IOW, il tipo di foo3 dovrebbe essere Hash (o dict ) invece di String , giusto? In tal caso, il codice sarebbe

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

e il risultato è

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"

In php potresti fare questo:

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

In Lua la struttura dei dati fondamentali è la tabella e persino l'ambiente globale _G è una tabella. Quindi, una semplice enumerazione farà il trucco.

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

IPython:

whos

Potresti anche raccomandare Spyder al tuo amico che mostra quelle variabili più o meno come fa Matlab e fornisce una GUI per il debug riga per riga.

Bash:

set

Disclaimer: non la mia lingua preferita!

Un one-liner PHP completamente ricorsivo:

print_r(get_defined_vars());

Per prima cosa, userei semplicemente un debugger ;-p Visual Studio, ad esempio, ha " Locals " e " Guarda " finestre che mostreranno tutte le variabili ecc. desiderate, completamente espandibili a qualsiasi livello.

In C # non puoi davvero ottenere molto facilmente le variabili del metodo (e molte sono ben rimosse dal compilatore) - ma puoi accedere ai campi ecc. tramite reflection:

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

Matlab:

who

Perl. Non gestisce i my locali e non filtra alcuni riferimenti inutili, ma è possibile vedere tutto nell'ambito del pacchetto.

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

In Java, il problema sarebbe simile a C #, solo in una modalità più dettagliata (lo so, LO SO ;) Java è dettagliato ... lo hai già chiarito;) )

È possibile accedere ai campi oggetto tramite Refection, ma non è possibile accedere facilmente alle variabili locali del metodo. Quindi non si tratta del codice di analisi statica, ma solo del debug di runtime.

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

In lingua R

ls()

e per rimuovere tutti gli oggetti dalla memoria di lavoro

rm(list=ls(all=TRUE))

In REBOL, tutte le variabili vivono all'interno di un contesto di tipo oggetto! . C'è un contesto globale e ogni funzione ha il suo contesto locale implicito. Puoi creare nuovi contesti esplicitamente creando un nuovo oggetto! (o usando la funzione context ). Questo è diverso dai linguaggi tradizionali perché le variabili (chiamate "parole" in REBOL) portano con sé un riferimento al loro contesto, anche quando hanno lasciato il "campo di applicazione" in cui sono stati definiti.

Quindi, la linea di fondo è che, dato un contesto, possiamo elencare le variabili che definisce. Useremo parole-contesto di Ladislav Mecir? .

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

Ora possiamo elencare tutte le parole definite nel contesto globale. (Ce ne sono molti .

probe context-words? system/words

Possiamo anche scrivere una funzione che elenca quindi le variabili che definisce.

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

Quello che non possiamo fare in REBOL, per quanto ne so, è risalire l'albero del contesto, anche se l'interprete sembra essere in grado di farlo perfettamente quando decide come legare parole nei loro contesti. Penso che ciò sia dovuto al fatto che l'albero del contesto (cioè l'ambito) può avere una "forma". al momento una parola è rilegata ma alquanto un'altra al momento in cui viene valutata.

Soluzione JavaScript rapida e sporca se è installato FireBug (o un altro browser con console.log). In caso contrario, dovrai cambiare console.log in document.write ed eseguire in uno script inline alla fine del tuo. Cambia MAX_DEPTH in quanti livelli di ricorsione desideri (fai attenzione!).

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

Lisp comune:

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

Per mostrare anche tutti i valori associati:

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

Questa è una lunga lista e non particolarmente utile. Vorrei davvero utilizzare il debugger integrato.

Ecco un'idea per le lingue straniere.

Per prima cosa hai bisogno di qualcosa come toString () in Java per stampare contenuti significativi. Secondo: devi limitarti a una gerarchia di oggetti. Nel costruttore dell'oggetto root (come Any in Eiffel), registra l'istanza al momento della creazione in una specie di elenco globale. Durante la distruzione, si annulla la registrazione (assicurarsi di utilizzare una struttura di dati che consenta l'inserimento / ricerca / rimozione rapidi). In qualsiasi momento durante l'esecuzione del programma, è possibile esplorare questa struttura di dati e stampare tutti gli oggetti ivi registrati.

A causa della sua struttura, Eiffel potrebbe essere molto buona per questo scopo. Altre lingue hanno problemi con oggetti che non sono definiti dall'utente (ad esempio le classi jdk). In Java potrebbe essere possibile creare la propria classe di oggetti usando un jdk open source.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top