枚举或列出[您在这里喜欢的语言]程序中的所有变量[关闭]


79

上周一个朋友问我如何枚举或列出程序/函数/等中的所有变量。出于调试目的(本质上是获取所有内容的快照,以便您可以看到设置了哪些变量,或者根本没有设置它们)。我环顾了一下,发现了使用Python的相对不错的方法:

#!/ usr / bin / python                                                                                                                                                                                                                           
foo1 =“你好世界”
foo2 =“ bar”
foo3 = {“ 1”:“ a”,
        “ 2”:“ b”}
foo4 =“ 1 + 1”

对于dir()中的名称:
    myvalue = eval(名称)
    打印名称,“是”,类型(名称),“和等于”,myvalue

这将输出类似:

__builtins__是<type'str'>并且等于<module'__builtin__'(内置)>
__doc__是<type'str'>,等于无
__file__是<type'str'>,等于./foo.py
__name__是<type'str'>,等于__main__
foo1是<type'str'>,等于Hello world
foo2是<type'str'>,等于bar
foo3是<type'str'>,等于{'1':'a','2':'b'}
foo4是<type'str'>,等于1 + 1

到目前为止,我已经在PHP中找到了一种局部方法(由link text提供),但是它只列出了所有变量及其类型,而不列出内容:

<?php
//创建一些变量
$ bar ='foo';
$ foo ='bar';
//创建一个新的数组对象
$ arrayObj =新的ArrayObject(get_defined_vars());
//遍历数组对象并回显变量和值
for($ iterator = $ arrayObj-> getIterator(); $ iterator-> valid(); $ iterator-> next())
        {
        echo $ iterator-> key()。'=>'。$ iterator-> current()。'<br />';
        }
?>

所以我告诉你:如何用自己喜欢的语言列出所有变量及其内容?


VonC编辑:我建议这个问题遵循一点“代码挑战”的精神。
如果您不同意,只需编辑并删除标签和链接。


4
在python中,我只使用locals / globals而不是上面显示的dir / eval。见下文。
亚伦·曼帕

在PHP中也可以轻松完成,请参阅我的答案。
Pim Jager

1
我不同意,我的计划是选择总体上最优雅的解决方案,并将其作为答案和前提。我想我是否会问每个问题中的一个,将其视为“适当的”问题,但值得注意的是,各种语言中使用的方法通常会与其他语言重叠(即使用调试器等)。
Kurt

1
很棒的帖子。我需要它来获取我在模块中定义的变量的列表。通过添加测试'not name.startswith('__')'(使用python),这确实令我惊讶。非常感谢
ShadowFlame 2012年

2
叹。两者都不应该同时是1)因为它是多种语言而过于宽泛而封闭; 2)是针对单一语言问题的“重复重定向”。
Charles Merriam

Answers:


93

在python中,使用locals返回包含所有本地绑定的字典,因此避免了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'>}

11

这就是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

将输出

foo1是String,等于“ Hello world”
foo2是String,等于“ bar”
foo3是String,等于{“ 1” =>“ a”,“ 2” =>“ b”}
foo4是String,等于“ 1 + 1”

但是,您不是要输出变量引用的对象类型,而不是用来表示变量标识符的类型吗?IOW,类型foo3应该是Hash(或dict)而不是String,对吗?在这种情况下,代码将是

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

结果是

foo1是String,等于“ Hello world”
foo2是String,等于“ bar”
foo3是Hash,等于{“ 1” =>“ a”,“ 2” =>“ b”}
foo4是String,等于“ 1 + 1”

1
您可能还应该包括:instance_variables global_variables class_variables常数
Rado 2010年

至少在ruby 2.2中,我不得不使用例如instance_variable_get(instance_variables[0])
jberryman's


9

在php中,您可以这样做:

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

3
+1不错,此功能有点晦涩难懂,但这是此处最小的示例之一,有些人还说PHP很烂。=)
Alix Axel

9

在Lua中,基本数据结构是,甚至全局环境_G都是表。因此,简单的枚举即可解决问题。

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



4

首先,我只是使用调试器;例如,Visual Studio具有“ Locals”和“ Watch”窗口,这些窗口将显示所需的所有变量等,并且可以完全扩展到任何级别。

在C#中,您不能真正轻松地获得方法变量(并且它们很容易被编译器删除)-但您可以通过反射来访问字段等:

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

Perl。不处理my本地语言,也不过滤掉一些无用的引用,但是可以看到包范围内的所有内容。

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



2

在Java中,问题将与C#相似,只是在更详细的模式下(我知道,我知道;)Java非常详细...您已经清楚了;)

您可以通过Refection访问对象字段,但是可能无法轻松访问方法局部变量。因此,以下内容不适用于静态分析代码,而仅适用于运行时调试。

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

或者,您可以使用Apache Commons Beanutils。
亚伦·迪古拉

冗长的不是Java,而是您的代码。首先AccessController是毫无意义的注释,再加上完全过时的操作,例如,在一个独立的应用程序中,整个处理是不必要的(setAccessible无论如何,对于访问您自己的字段都是不必要的),或者该if语句可以区分两种可以处理的情况。删除过时的toString()呼叫时的方法相同:System.out.println(aField.getName() + ": " + res);无论是否有效,res均有效null。而且也无需将代码散布到多种方法中……
Holger

1

在REBOL中,所有变量都位于type的上下文object!。有一个全局上下文,每个函数都有其自己的隐式局部上下文。您可以通过创建新上下文object!(或使用context函数)来显式创建新上下文。这与传统语言不同,因为变量(在REBOL中称为“单词”)携带了对其周围环境的引用,即使它们离开了定义它们的“范围”。

因此,最重要的是,在给定上下文的情况下,我们可以列出其定义的变量。我们将使用Ladislav Mecircontext-words?函数。

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

现在,我们可以列出全局上下文中定义的所有单词。(有很多。)

probe context-words? system/words

我们还可以编写一个函数,然后列出它定义的变量。

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

据我所知,在REBOL中我们无法做的是沿上下文树走,尽管在决定如何将单词绑定到上下文时,解释器似乎能够很好地做到这一点。我认为这是因为上下文树(即作用域)在绑定一个单词时可能具有一种“形状”,而在其被评估时却具有另一种“形状”。


1

快速且肮脏的JavaScript解决方案(如果您安装了FireBug)(或安装了console.log的其他浏览器)。如果不这样做,则必须将console.log更改为document.write,并在末尾以内联脚本的身份运行。将MAX_DEPTH更改为所需的递归级别(请注意!)。

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

0

普通Lisp:

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

同时显示所有绑定值:

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

这是一个很长的列表,并不是特别有用。我真的会使用集成调试器。


0

这是一个面向对象语言的想法。

首先,您需要使用Java中的toString()之类的东西来打印有意义的内容。第二-您必须将自己限制在一个对象层次结构中。在根对象的构造函数中(如Eiffel中的Any),在创建实例时会在某种全局列表中进行注册。在销毁过程中,您要注销(请确保使用某些允许快速插入/搜索/删除的数据结构)。在程序执行期间的任何时间,您都可以遍历此数据结构并打印在那里注册的所有对象。

由于其结构,Eiffel可能非常适合此目的。其他语言对非用户定义的对象(例如jdk类)存在问题。在Java中,可能可以使用某些开源jdk创建自己的Object-class。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.