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

80

Un amigo me preguntó la semana pasada cómo enumerar o enumerar todas las variables dentro de un programa / función / etc. con el propósito de depurar (básicamente, obtener una instantánea de todo para que pueda ver en qué variables están configuradas, o si están configuradas). Miré un poco a mi alrededor y encontré una forma relativamente buena de Python:

#! / usr / bin / python                                                                                                                                                                                                                           
foo1 = "Hola mundo"
foo2 = "barra"
foo3 = {"1": "a",
        "2": "b"}
foo4 = "1 + 1"

para el nombre en dir ():
    myvalue = eval (nombre)
    imprimir nombre, "es", tipo (nombre), "y es igual a", myvalue

que dará como resultado algo como:

__builtins__ es <tipo 'str'> y es igual a <módulo '__builtin__' (integrado)>
__doc__ es <tipo 'str'> y es igual a Ninguno
__file__ es <tipo 'str'> y es igual a ./foo.py
__name__ es <tipo 'str'> y es igual a __main__
foo1 es <tipo 'str'> y es igual a Hola mundo
foo2 es <tipo 'str'> y es igual a bar
foo3 es <tipo 'str'> y es igual a {'1': 'a', '2': 'b'}
foo4 es <tipo 'str'> y es igual a 1 + 1

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

<? php
// crea algunas variables
$ bar = 'foo';
$ foo = 'barra';
// crea un nuevo objeto de matriz
$ arrayObj = new ArrayObject (get_defined_vars ());
// bucle sobre el objeto de matriz y echo variables y valores
para ($ iterador = $ arrayObj-> getIterator (); $ iterator-> valid (); $ iterator-> next ())
        {
        echo $ iterador-> tecla (). '=>'. $ iterador-> actual (). '<br />';
        }
?>

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


Editar por VonC : Propongo que esta pregunta sigue el espíritu de un pequeño " desafío de código ".
Si no está de acuerdo, simplemente edite y elimine la etiqueta y el enlace.

Kurt
fuente
4
En Python, solo usaría locals / globals en lugar del dir / eval que muestra arriba. Vea abajo.
Aaron Maenpaa
En PHP también se puede hacer mucho más fácil, vea mi respuesta.
Pim Jager
1
No estoy de acuerdo, mi plan es elegir la solución más elegante en general y establecerla como la respuesta y listo. Supongo que si hubiera preguntado uno de estos para cada pregunta individual, eso calificaría más como una pregunta "adecuada", pero vale la pena señalar que los métodos utilizados en varios idiomas a menudo se superponen con otros idiomas (es decir, use el depurador / etc.).
Kurt
1
buena publicación. Necesitaba esto para obtener una lista de variables que definí en un módulo. con una prueba adicional de 'not name.startswith (' __ ')' (usando python) esto hace maravillas para mí. Muchas gracias
ShadowFlame
2
Suspiro. No deben ser ambos 1) cerrados por ser demasiado amplios porque es de varios idiomas y 2) ser el "redireccionamiento duplicado" para preguntas de un solo idioma.
Charles Merriam

Respuestas:

93

En python, el uso de locales que devuelve un diccionario que contiene todos los enlaces locales, evitando así 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'>}
Aaron Maenpaa
fuente
11

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 saldrá

foo1 es String y es igual a "Hola mundo"
foo2 es String y es igual a "bar"
foo3 es String y es igual a {"1" => "a", "2" => "b"}
foo4 es String y es igual a "1 + 1"

Sin embargo, ¿no pretendía generar el 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 foo3deberí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 es String y es igual a "Hola mundo"
foo2 es String y es igual a "bar"
foo3 es Hash y es igual a {"1" => "a", "2" => "b"}
foo4 es String y es igual a "1 + 1"
Jörg W Mittag
fuente
1
probablemente también debería incluir: instance_variables global_variables class_variables constants
Rado
Al menos en ruby ​​2.2 tuve que usar, por ejemploinstance_variable_get(instance_variables[0])
jberryman
10

IPython:

whos

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

Eder Santana
fuente
9

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>";
}
Pim Jager
fuente
3
+1 Bien, esta función es un poco oscura, pero este es uno de los ejemplos más pequeños aquí, y algunos todavía dicen que PHP apesta. =)
Alix Axel
9

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

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

Intento:

set

Descargo de responsabilidad: ¡No es mi idioma favorito!

demasiado php
fuente
3
Compare con envpara averiguar los valores no exportados.
Nitrodist
6

Una línea de PHP completamente recursiva:

print_r(get_defined_vars());
LapTop006
fuente
4

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

En C # realmente no puede acceder a las variables de método con mucha facilidad (y es posible que el compilador las elimine), 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);
            }
        }
    }
}
Marc Gravell
fuente
4

Perl. No maneja mylocales 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";
}
efímero
fuente
3

En el lenguaje R

ls()

y eliminar todos los objetos de la memoria de trabajo

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

En Java, el problema sería similar a C #, sólo en un modo más detallado (lo sé, ;) Java es prolijo ... que hizo que ya está claro;) )

Puede acceder a los campos de objeto a través de Refection, pero es posible que no acceda fácilmente a las variables locales del método. Entonces, lo siguiente no es para código de análisis estático, sino solo para 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");
            }
        }
    }
}
VonC
fuente
O puede utilizar Apache Commons Beanutils.
Aaron Digulla
No es Java lo que es detallado, sino su código. Comentarios sin sentido, para empezar, además de operaciones completamente obsoletas, por ejemplo, todo el tratamiento AccessControlleres innecesario en una aplicación independiente (bueno, setAccessiblees innecesario para acceder a sus propios campos de todos modos) o la ifdeclaración para diferenciar entre dos casos que se pueden manejar de la misma manera al eliminar la toString()llamada obsoleta : System.out.println(aField.getName() + ": " + res);funciona, independientemente de si lo reses nullo no. Y tampoco es necesario difundir el código en varios métodos…
Holger
1

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

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

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

Ahora podemos enumerar todas las palabras definidas en el contexto global. (Hay muchos 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, que yo sepa, es subir por el árbol de contexto, aunque el intérprete parece ser capaz de hacerlo perfectamente bien cuando decide cómo unir las 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 enlaza una palabra, pero otra muy distinta en el momento en que se evalúa.

Gregory Higley
fuente
1

Solución de JavaScript rápida y sucia si tiene FireBug instalado (u otro navegador con console.log). Si no lo hace, tendrá que cambiar console.log a document.write y ejecutar en como un script en línea al final de su. Cambie MAX_DEPTH a la cantidad de niveles de recursividad que desee (¡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);
    }
})();
gregers
fuente
0

Lisp común:

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

Para mostrar también todos los valores vinculados:

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

Svante
fuente
0

Aquí tienes una idea para oo-languages.

Primero necesita algo como toString () en Java para imprimir contenido significativo. En segundo lugar, debe limitarse a una jerarquía de objetos. En el constructor del objeto raíz (como Any en Eiffel), registra la instancia al crearse 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 rápida inserción / búsqueda / eliminación). 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.

Tobias Langner
fuente