Enumere o enumere todas las variables en un programa de [su idioma favorito aquí] [cerrado]
-
08-07-2019 - |
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.
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.