Enumere o enumere todas las variables en un programa de [su idioma favorito aquí] [cerrado]

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

Pregunta

Un amigo me preguntó la semana pasada cómo enumerar o enumerar todas las variables dentro de un programa / función / etc. con el fin de depurar (esencialmente obtener una instantánea de todo para que pueda ver qué variables están configuradas, o si están configuradas). Miré un poco a mi alrededor y encontré una forma relativamente buena para 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

que generará algo como:

__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

Hasta ahora he encontrado una forma parcial en PHP (cortesía de texto del enlace ) pero solo enumera todas las variables y sus tipos, no los contenidos:

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

Así que te lo digo: ¿cómo enumeras todas las variables y sus contenidos en tu idioma favorito?


Editar por VonC : Propongo que esta pregunta siga el espíritu de un pequeño " code-challenge " ;.
Si no está de acuerdo, simplemente edite y elimine la etiqueta y el enlace.

¿Fue útil?

Solución

En python, usando locales que devuelve un diccionario que contiene todos los enlaces locales, evitando así evaluar:

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

Otros consejos

Así es como se vería en 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

que dará salida

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"

Sin embargo, ¿no quiso dar salida al tipo de objeto al que hace referencia la variable en lugar del tipo utilizado para representar el identificador de la variable? IOW, el tipo de foo3 debería ser Hash (o dict ) en lugar de String , ¿verdad? En ese caso, el código sería

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

y el resultado es

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 puedes hacer esto:

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

En Lua, la estructura de datos fundamental es la tabla e incluso el entorno global _G es una tabla. Entonces, una simple enumeración hará el truco.

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

IPython:

whos

También podría recomendar Spyder a su amigo, que muestra esas variables de manera muy similar a Matlab y proporciona una GUI para la depuración línea por línea.

Bash:

set

Descargo de responsabilidad: ¡No es mi idioma favorito!

Una línea de PHP completamente recursiva:

print_r(get_defined_vars());

Primero, simplemente usaría un depurador ;-p Visual Studio, por ejemplo, tiene "Locales". y "Ver" ventanas que mostrarán todas las variables, etc. que desee, completamente expandibles a cualquier nivel.

En C # realmente no se puede acceder a las variables de método con mucha facilidad (y el compilador puede eliminarlas), pero puede acceder a los campos, etc. mediante la reflexión:

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. No maneja my locales, y no filtra algunas referencias inútiles, pero se puede ver todo en el alcance del paquete.

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, el problema sería similar a C #, solo en un modo más detallado (lo sé, LO SÉ ;) Java es detallado ... ya lo dejó claro;) )

Puede acceder a los campos de objetos a través de Refection, pero no puede acceder fácilmente a las variables locales del método. Por lo tanto, lo siguiente no es para el código de análisis estático, sino solo para la depuración en tiempo de ejecución.

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 el lenguaje R

ls()

y para eliminar todos los objetos de la memoria de trabajo

rm(list=ls(all=TRUE))

En REBOL, todas las variables viven dentro de un contexto de tipo objeto! . Hay un contexto global, y cada función tiene su propio contexto local implícito. Puede crear nuevos contextos explícitamente creando un nuevo objeto ! (o utilizando la función context ). Esto es diferente de los lenguajes tradicionales porque las variables (llamadas "palabras" en REBOL) llevan consigo una referencia a su contexto, incluso cuando han dejado el "alcance". en que fueron definidos.

Entonces, la conclusión es que, dado un contexto, podemos enumerar las variables que define. Utilizaremos las context-words de Ladislav Mecir. función.

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

Ahora podemos enumerar todas las palabras definidas en el contexto global. (Hay un lote de ellos).

probe context-words? system/words

También podemos escribir una función que luego enumere las variables que define.

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

Lo que no podemos hacer en REBOL, hasta donde yo sé, es caminar por el árbol de contexto, aunque el intérprete parece ser capaz de hacerlo perfectamente cuando decide cómo vincular palabras a sus contextos. Creo que esto se debe a que el árbol de contexto (es decir, el alcance) puede tener una '' forma '' en el momento en que se vincula una palabra, pero en otra muy distinta en el momento en que se evalúa.

Solución JavaScript rápida y sucia si tiene instalado FireBug (u otro navegador con console.log). Si no lo hace, tendrá que cambiar console.log a document.write y ejecutarlo como un script en línea al final de su. Cambie MAX_DEPTH a cuántos niveles de recursión desea (¡tenga cuidado!).

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

Para mostrar también todos los valores enlazados:

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

Esta es una lista larga, y no particularmente útil. Realmente usaría el depurador integrado.

Aquí hay una idea para oo-languages.

Primero necesita algo como toString () en Java para imprimir contenidos significativos. Segundo: tienes que restringirte a una jerarquía de objetos. En el constructor del objeto raíz (como Any en Eiffel), registra la instancia después de la creación en algún tipo de lista global. Durante la destrucción, cancela el registro (asegúrese de utilizar alguna estructura de datos que permita una inserción / búsqueda / eliminación rápidas). En cualquier momento durante la ejecución del programa, puede recorrer esta estructura de datos e imprimir todos los objetos registrados allí.

Debido a su estructura, Eiffel podría ser muy bueno para este propósito. Otros lenguajes tienen problemas con objetos que no están definidos por el usuario (por ejemplo, las clases jdk). En Java podría ser posible crear su propia clase de Objeto utilizando algún jdk de código abierto.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top