web-dev-qa-db-fra.com

Énumérer ou lister toutes les variables dans un programme de [votre langue préférée ici]

Un ami m'a demandé la semaine dernière comment énumérer ou lister toutes les variables d'un programme/fonction/etc. à des fins de débogage (essentiellement, obtenir un instantané de tout pour que vous puissiez voir quelles variables sont définies ou si elles le sont). J'ai regardé un peu autour et trouvé un moyen relativement bon pour Python:

 #!/usr/bin/python 
 foo1 = "Bonjour tout le monde" 
 foo2 = "bar" 
 foo3 = {"1": "a", 
 "2": "b"} 
 Foo4 = "1 + 1" 

 Pour le nom dans dir (): 
 myvalue = eval (nom) 
 Nom d'impression, "est", type (nom), "et est égal à", myvalue 

qui produira quelque chose comme:

__ builtins__ est <type 'str'> et est égal à <module '__builtin__' (intégré)> 
__ doc__ est <type 'str'> et égal à Aucun 
__ fichier__ est <type ' str '> et est égal à ./foo.py
__est <type' str '> et égal à __main __
 foo1 est <type' str '> et égal à Hello world 
 foo2 est <type 'str'> et est égal à bar 
 foo3 est <type 'str'> et est égal à {'1': 'a', '2': 'b'} 
 foo4 est <type 'str'> et est égal à 1 + 1 

J'ai jusqu'à présent trouvé un moyen partiel dans PHP (courtoisie de link text ) mais il ne répertorie que toutes les variables et leurs types, pas le contenu:

 <? php
// créer quelques variables 
 $ bar = 'foo'; 
 $ foo = 'bar'; 
 // créer un nouvel objet tableau 
 $ arrayObj = new ArrayObject (get_defined_vars ()); 
 // boucle sur l'objet et les variables et valeurs d'écho 
 pour ($ iterator = $ arrayObj-> getIterator (); $ iterator-> valid (); $ iterator -> next ()) 
 {
 echo $ iterator-> key (). '=>'. $ iterator-> current (). '<br />'; 
 } 
?> 

Alors je vous pose la question suivante: comment lister toutes les variables et leur contenu dans votre langue préférée?


Edit by VonC : Je propose que cette question suive l’esprit d’un petit " code-challenge ".
Si vous ne les acceptez pas, éditez et supprimez simplement le tag et le lien.

74
Kurt

En python, en utilisant des locales qui retourne un dictionnaire contenant toutes les liaisons locales, évitant ainsi 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'>}
85
Aaron Maenpaa

Voici à quoi cela ressemblerait dans 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

qui va sortir

foo1 est String et est égal à "Hello world" 
 foo2 est String et est égal à "bar" 
 foo3 est String et est égal à {"1" => "a", "2" => " b "} 
 foo4 est une chaîne et est égal à" 1 + 1 "

Cependant, n’avez-vous pas voulu sortir le type d’objet avec les références de variable au lieu du type utilisé pour représenter l’identificateur de variable? IOW, le type de foo3 devrait être Hash (ou dict) au lieu de String, non? Dans ce cas, le code serait

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

et le résultat est

foo1 est String et est égal à "Hello world" 
 foo2 est String et est égal à "bar" 
 foo3 est Hash et est égal à {"1" => "a", "2" => " b "} 
 foo4 est une chaîne et est égal à" 1 + 1 "
11
Jörg W Mittag

En php, vous pouvez faire ceci:

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

Dans Lua, la structure de données fondamentale est la table et même l’environnement global _G est une table. Donc, une simple énumération fera l'affaire.

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

Bash:

set

Disclaimer: Pas ma langue préférée!

6
too much php

Un one-liner PHP entièrement récursif:

print_r(get_defined_vars());
6
LapTop006

IPython:

whos

Vous pouvez également recommander Spyder à votre ami, qui affiche ces variables comme le fait Matlab et fournit une interface graphique pour le débogage ligne par ligne. 

6
Eder Santana

Matlab:

who
4
Dario

D'abord, j'utiliserais simplement un débogueur ;-p Visual Studio, par exemple, a des fenêtres "Locals" et "Watch" qui affichent toutes les variables souhaitées, etc., entièrement extensibles à n'importe quel niveau.

En C #, vous ne pouvez pas vraiment accéder facilement aux variables de méthode (et elles peuvent bien souvent être supprimées par le compilateur) - mais vous pouvez accéder à des champs, etc., par réflexion:

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
Marc Gravell

Perl. Ne gère pas les variables locales my, et ne filtre pas certaines références inutiles, mais tout ce qui se trouve dans la portée du paquet est visible.

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

En Java, le problème serait similaire à C #, mais en mode plus verbeux (je sais, JE SAIS;) Java est verbeux ... vous l'avez déjà expliqué;) )

Vous pouvez accéder aux champs d'objet via Refection, mais vous ne pouvez pas accéder facilement aux variables locales de la méthode. Ce qui suit ne concerne donc pas le code d'analyse statique, mais uniquement le débogage à l'exécution.

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

Dans le langage R 

ls()

et supprimer tous les objets de la mémoire de travail

rm(list=ls(all=TRUE))
2
Tiago Zortea

Solution JavaScript rapide et sale si vous avez installé FireBug (ou un autre navigateur avec console.log). Si vous ne le faites pas, vous devrez remplacer console.log par document.write et le lancer en tant que script intégré à la fin de votre. Modifiez MAX_DEPTH en fonction du nombre de niveaux de récursivité souhaité (soyez prudent!).

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

Dans REBOL, toutes les variables résident dans un contexte de type _object!_. Il y a un contexte global et chaque fonction a son propre contexte local implicite. Vous pouvez créer explicitement de nouveaux contextes en créant un nouveau _object!_ (ou en utilisant la fonction context.). Cela diffère des langages traditionnels car les variables (appelées "mots" dans REBOL) portent avec elles une référence à leur contexte, même lorsqu'elles ont quitté la "portée" dans laquelle elles ont été définies.

En résumé, dans un contexte, nous pouvons répertorier les variables qu’il définit. Nous utiliserons la fonction context-words? de Ladislav Mecir.

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

Nous pouvons maintenant lister tous les mots définis dans le contexte global. (Il en existe beaucoup .)

_probe context-words? system/words
_

Nous pouvons également écrire une fonction qui liste ensuite les variables qu’elle définit.

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

Ce que nous ne pouvons pas faire dans REBOL, pour autant que je sache, marche dans l’arborescence du contexte, bien que l’interprète semble pouvoir le faire. parfaitement bien quand il décide comment lier les mots à leurs contextes. Je pense que cela est dû au fait que l’arborescence du contexte (c’est-à-dire la portée) peut avoir une "forme" au moment où un mot est lié, mais une autre au moment de son évaluation.

1
Gregory Higley

Voici une idée pour oo-languages.

Tout d'abord, vous avez besoin de quelque chose comme toString () en Java pour imprimer un contenu significatif ..__ Deuxièmement, vous devez vous limiter à une hiérarchie d'objets. Dans le constructeur de l'objet racine (comme Any dans Eiffel), vous enregistrez l'instance lors de la création dans une sorte de liste globale. Lors de la destruction, vous désenregistrez (veillez à utiliser une structure de données permettant une insertion/recherche/suppression rapide). À tout moment pendant l'exécution du programme, vous pouvez parcourir cette structure de données et imprimer tous les objets qui y sont enregistrés.

En raison de sa structure, Eiffel pourrait être très utile à cette fin. D'autres langues ont des problèmes avec des objets qui ne sont pas définis par l'utilisateur (par exemple, les classes jdk). En Java, il peut être possible de créer votre propre classe Object en utilisant un jdk open source.

0
Tobias Langner

LISP commun:

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

Pour afficher également toutes les valeurs liées:

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

C'est une longue liste, et pas particulièrement utile. Je voudrais vraiment utiliser le débogueur intégré.

0
Svante