Liệt kê hoặc liệt kê tất cả các biến trong chương trình của [ngôn ngữ yêu thích của bạn tại đây] [đã đóng]


80

Tuần trước, một người bạn đã hỏi tôi cách liệt kê hoặc liệt kê tất cả các biến trong một chương trình / hàm / v.v. cho mục đích gỡ lỗi (về cơ bản là lấy ảnh chụp nhanh của mọi thứ để bạn có thể xem những biến nào được đặt thành hoặc nếu chúng được đặt ở tất cả). Tôi đã xem xét xung quanh một chút và tìm thấy một cách tương đối tốt cho Python:

#! / usr / bin / python                                                                                                                                                                                                                           
foo1 = "Xin chào thế giới"
foo2 = "thanh"
foo3 = {"1": "a",
        "2": "b"}
foo4 = "1 + 1"

cho tên trong dir ():
    myvalue = eval (tên)
    print name, "is", type (name), "và bằng", myvalue

sẽ xuất ra một cái gì đó như:

__builtins__ là <type 'str'> và bằng <module '__builtin__' (tích hợp sẵn)>
__doc__ là <type 'str'> và bằng Không
__file__ là <type 'str'> và bằng ./foo.py
__name__ là <type 'str'> và bằng __main__
foo1 là <type 'str'> và bằng Hello world
foo2 là <type 'str'> và bằng với thanh
foo3 là ​​<type 'str'> và bằng {'1': 'a', '2': 'b'}
foo4 là <type 'str'> và bằng 1 + 1

Cho đến nay, tôi đã tìm thấy một phần cách trong PHP (nhờ vào văn bản liên kết ) nhưng nó chỉ liệt kê tất cả các biến và kiểu của chúng chứ không phải nội dung:

<? php
// tạo một vài biến
$ bar = 'foo';
$ foo = 'thanh';
// tạo một đối tượng mảng mới
$ arrayObj = new ArrayObject (get_defined_vars ());
// lặp qua đối tượng mảng và các biến và giá trị echo
for ($ iterator = $ arrayObj-> getIterator (); $ iterator-> valid (); $ iterator-> next ())
        {
        echo $ iterator-> key (). '=>'. $ iterator-> current (). '<br />';
        }
?>

Vì vậy, tôi đặt nó cho bạn: làm thế nào để bạn liệt kê tất cả các biến và nội dung của chúng bằng ngôn ngữ yêu thích của bạn?


Chỉnh sửa bởi VonC : Tôi đề xuất câu hỏi này theo tinh thần của một chút " thử thách mã ".
Nếu bạn không đồng ý, chỉ cần chỉnh sửa và xóa thẻ và liên kết.


4
Trong python, tôi chỉ sử dụng local / global thay vì dir / eval mà bạn hiển thị ở trên. Xem bên dưới.
Aaron Maenpaa

Trong PHP, nó cũng có thể được thực hiện dễ dàng hơn nhiều, hãy xem câu trả lời của tôi.
Pim Jager

1
Tôi không đồng ý, kế hoạch của tôi là chọn giải pháp tổng thể thanh lịch nhất và đặt đó làm câu trả lời và bắt đầu. Tôi cho rằng nếu tôi hỏi một trong những câu hỏi này cho từng câu hỏi riêng lẻ sẽ đủ điều kiện hơn là một câu hỏi "thích hợp" nhưng cần lưu ý rằng các phương pháp được sử dụng trong các ngôn ngữ khác nhau thường trùng lặp với các ngôn ngữ khác (tức là sử dụng trình gỡ lỗi / v.v.).
Kurt

1
bài viết tuyệt vời. Tôi cần điều này để có được danh sách các biến mà tôi đã xác định trong một mô-đun. với một thử nghiệm được thêm vào 'not name.startswith (' __ ')' (sử dụng python), điều này thực sự kỳ diệu đối với tôi. Thanks a lot
ShadowFlame

2
Thở dài. Không nên cho cả hai là 1) đóng vì quá rộng vì nó gồm nhiều ngôn ngữ và 2) là "chuyển hướng trùng lặp" cho các câu hỏi của một ngôn ngữ.
Charles Merriam

Câu trả lời:


93

Trong python, sử dụng local sẽ trả về một từ điển chứa tất cả các ràng buộc cục bộ, do đó, tránh được 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

Đây là những gì nó sẽ giống như trong 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

cái nào sẽ xuất ra

foo1 là Chuỗi và bằng "Hello world"
foo2 là Chuỗi và bằng "bar"
foo3 là ​​Chuỗi và bằng {"1" => "a", "2" => "b"}
foo4 là Chuỗi và bằng "1 + 1"

Tuy nhiên, ý của bạn không phải là xuất ra kiểu đối tượng mà biến tham chiếu thay vì kiểu được sử dụng để đại diện cho định danh biến? IOW, loại foo3nên là Hash(hoặc dict) thay vì String, phải không? Trong trường hợp đó, mã sẽ là

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

và kết quả là

foo1 là Chuỗi và bằng "Hello world"
foo2 là Chuỗi và bằng "bar"
foo3 là ​​Hash và bằng {"1" => "a", "2" => "b"}
foo4 là Chuỗi và bằng "1 + 1"

1
bạn cũng nên có lẽ bao gồm: instance_variables global_variables class_variables hằng
Rado

Ít nhất trong ruby 2.2 Tôi đã phải sử dụng ví dụinstance_variable_get(instance_variables[0])
jberryman

10

IPython:

whos

Bạn cũng có thể giới thiệu Spyder cho bạn bè của mình, nó hiển thị các biến đó khá giống Matlab và cung cấp GUI để gỡ lỗi từng dòng.


9

Trong php, bạn có thể làm điều này:

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

3
+1 Tuyệt vời, hàm này hơi khó hiểu nhưng đây là một trong những ví dụ nhỏ nhất ở đây và một số người vẫn nói PHP tệ. =)
Alix Axel

9

Trong Lua, cấu trúc dữ liệu cơ bản là bảng và thậm chí môi trường toàn cục _G là một bảng. Vì vậy, một phép liệt kê đơn giản sẽ làm được thủ thuật.

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

6

Bash:

set

Tuyên bố từ chối trách nhiệm: Không phải ngôn ngữ yêu thích của tôi!


3
So sánh với envđể tìm ra các giá trị không được xuất.
Nitrodist

6

Một lớp lót PHP đệ quy đầy đủ:

print_r(get_defined_vars());

4

Đầu tiên, tôi chỉ đơn giản sử dụng trình gỡ lỗi; ví dụ như Visual Studio, có cửa sổ "Locals" và "Watch" sẽ hiển thị tất cả các biến, v.v. bạn muốn, hoàn toàn có thể mở rộng đến bất kỳ cấp nào.

Trong C #, bạn thực sự không thể truy cập các biến phương thức rất dễ dàng (và nhiều biến phương thức cũng bị loại bỏ bởi trình biên dịch) - nhưng bạn có thể truy cập các trường, v.v. thông qua phản chiếu:

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. Không xử lý các mylocal và không lọc ra một số tham chiếu vô ích, nhưng mọi thứ trong phạm vi gói đều có thể được nhìn thấy.

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


3

Bằng ngôn ngữ R

ls()

và xóa tất cả các đối tượng khỏi bộ nhớ làm việc

rm(list=ls(all=TRUE))

2

Trong java, vấn đề sẽ tương tự như C #, chỉ ở một chế độ dài dòng hơn (Tôi biết, tôi BIẾT ;) Java là dài dòng ... bạn đã làm rõ điều đó rồi;) )

Bạn có thể truy cập vào các trường đối tượng thông qua Refection, nhưng bạn có thể không truy cập dễ dàng vào các biến cục bộ của phương thức. Vì vậy, phần sau không dành cho mã phân tích tĩnh, mà chỉ dành cho gỡ lỗi thời gian chạy.

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

Hoặc bạn có thể sử dụng Apache Commons Beanutils.
Aaron Digulla

Nó không phải là Java dài dòng, mà là mã của bạn. Nhận xét vô nghĩa, bắt đầu, cộng với các hoạt động hoàn toàn lỗi thời, ví dụ: toàn bộ việc xử lý AccessControllerlà không cần thiết trong một ứng dụng độc lập ( setAccessibledù sao thì cũng không cần thiết để truy cập các trường của riêng bạn) hoặc ifcâu lệnh để phân biệt giữa hai trường hợp có thể xử lý cùng cách khi loại bỏ các lỗi thời toString()gọi: System.out.println(aField.getName() + ": " + res);công trình, bất kể resnullhay không. Và cũng không cần phải trải mã qua nhiều phương pháp…
Holger

1

Trong REBOL, tất cả các biến đều nằm trong ngữ cảnh của kiểu object!. Có một ngữ cảnh toàn cầu và mỗi hàm đều có ngữ cảnh cục bộ ngầm định của riêng nó. Bạn có thể tạo ngữ cảnh mới một cách rõ ràng bằng cách tạo mới object!(hoặc sử dụng contexthàm). Điều này khác với các ngôn ngữ truyền thống vì các biến (được gọi là "từ" trong REBOL) mang một tham chiếu đến ngữ cảnh xung quanh chúng, ngay cả khi chúng đã rời khỏi "phạm vi" mà chúng đã được xác định.

Vì vậy, điểm mấu chốt là, với một ngữ cảnh, chúng ta có thể liệt kê các biến mà nó xác định. Chúng tôi sẽ sử dụng context-words?chức năng của Ladislav Mecir .

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

Bây giờ chúng ta có thể liệt kê tất cả các từ được định nghĩa trong ngữ cảnh toàn cục. (Có rất nhiều trong số chúng.)

probe context-words? system/words

Chúng ta cũng có thể viết một hàm sau đó liệt kê các biến mà nó định nghĩa.

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

Những gì chúng ta không thể làm trong REBOL, theo như tôi biết, là đi lên cây ngữ cảnh, mặc dù trình thông dịch dường như có thể làm điều này hoàn toàn tốt khi nó quyết định cách liên kết các từ với ngữ cảnh của chúng. Tôi nghĩ điều này là do cây ngữ cảnh (tức là phạm vi) có thể có một "hình dạng" tại thời điểm một từ bị ràng buộc nhưng hoàn toàn khác tại thời điểm nó được đánh giá.


1

Giải pháp JavaScript nhanh và bẩn nếu bạn đã cài đặt FireBug (hoặc một trình duyệt khác có console.log). Nếu không, bạn sẽ phải thay đổi console.log thành document.write và chạy dưới dạng tập lệnh nội tuyến ở cuối của bạn. Thay đổi MAX_DEPTH thành bao nhiêu mức đệ quy bạn muốn (hãy cẩn thận!).

(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 chung:

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

Để cũng hiển thị tất cả các giá trị bị ràng buộc:

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

Đây là một danh sách dài và không đặc biệt hữu ích. Tôi thực sự sẽ sử dụng trình gỡ lỗi tích hợp.


0

Đây là một ý tưởng cho ngôn ngữ oo.

Đầu tiên, bạn cần một cái gì đó như toString () trong Java để in nội dung có ý nghĩa. Thứ hai - bạn phải tự giới hạn mình trong một hệ thống phân cấp đối tượng. Trong phương thức khởi tạo của đối tượng gốc (như Any trong Eiffel), bạn đăng ký thể hiện khi tạo trong một số loại danh sách chung. Trong quá trình phá hủy, bạn hủy đăng ký (hãy đảm bảo sử dụng một số cấu trúc dữ liệu cho phép chèn / tìm kiếm / loại bỏ nhanh chóng). Bất kỳ lúc nào trong quá trình thực thi chương trình, bạn có thể xem qua cấu trúc dữ liệu này và in tất cả các đối tượng đã đăng ký ở đó.

Do cấu trúc của nó, Eiffel có thể rất tốt cho mục đích này. Các ngôn ngữ khác gặp sự cố với các đối tượng không do người dùng định nghĩa (ví dụ: lớp jdk). Trong Java, bạn có thể tạo lớp Đối tượng của riêng mình bằng một số jdk mã nguồn mở.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.