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

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

Question

Un ami m'a demandé la semaine dernière comment énumérer ou répertorier toutes les variables d'un programme / fonction / etc. à des fins de débogage (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 = "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

qui produira quelque chose comme:

__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

J'ai jusqu'à présent trouvé une solution partielle à PHP (avec la permission de texte du lien ) mais il ne répertorie que toutes les variables et leurs types, pas le contenu:

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

Je vous ai donc posé la question suivante: comment répertorier toutes les variables et leur contenu dans votre langue préférée?

Modifier de 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.

Était-ce utile?

La solution

En python, utilisation de paramètres locaux qui renvoie 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'>}

Autres conseils

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

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"

Cependant, n’avez-vous pas voulu indiquer le type d’objet que la variable fait référence à la place du type utilisé pour représenter l’identificateur de la variable? IOW, le type de foo3 doit être Hash (ou dict ) au lieu de String , n'est-ce pas? 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 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"

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

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

IPython:

whos

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

Bash:

set

Avertissement: Ce n'est pas ma langue préférée!

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

print_r(get_defined_vars());

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

En C #, vous ne pouvez pas vraiment accéder aux variables de méthode (et elles sont souvent 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);
            }
        }
    }
}

Matlab:

who

Perl. Ne gère pas les mes locals, et ne filtre pas certaines références inutiles, mais tout dans l'étendue du paquet peut être vu.

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

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

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

En langage R

ls()

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

rm(list=ls(all=TRUE))

Dans REBOL, toutes les variables résident dans un contexte de type objet! . 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 nouvel objet ! (ou en utilisant la fonction context ). Ceci est différent des langages traditionnels car les variables (appelées "mots" dans REBOL) portent une référence à leur contexte, même lorsqu'elles ont quitté la "portée". dans lequel ils ont été définis.

La conclusion est donc que, dans un contexte, nous pouvons lister les variables qu’il définit. Nous utiliserons les mots de contexte de Ladislav Mecir? fonction.

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

Nous pouvons maintenant lister tous les mots définis dans le contexte global. (Il y en a 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, c’est de parcourir l’arborescence du contexte, bien que l’interprète semble être capable de le faire parfaitement 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 tout à fait un autre au moment où il est évalué.

Solution JavaScript rapide et sale si vous avez installé FireBug (ou un autre navigateur avec console.log). Sinon, vous devrez remplacer console.log par document.write et exécuter le script in à la fin de votre script. 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);
    }
})();

Common Lisp:

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

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

Voici une idée pour les o-langues.

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 seule hiérarchie d'objets. Dans le constructeur de l'objet racine (comme Any dans Eiffel), vous enregistrez l'instance à 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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top