调试时加打印方法

博客介绍了打印信息时带上文件名、方法名和行号的内容,转载自https://www.cnblogs.com/qiangge-python/p/10823396.html 。

打印信息带文件名+方法名+行号

 

package ...


import android.support.annotation.Nullable;
import android.util.Log;

/**
 *
 */
public class Zprint {

    /**
     * @param object 传入Class类型 可以用getClass()得到
     * @param key    要输出数据的标识
     * @param out    动态参数,这里是要输出的数据
     */
    public static void log(Class<?> object, @Nullable String key, Object... out) {
        if (!BuildConfig.DEBUG) {
            return;
        }
        boolean next = false;//判断是否含有 lambda 表达式
        String methodName;

        String className = object.getName();
        if (className == null || className.isEmpty()) {
            return;
        } else if (className.contains("$")) { //用于内部类的名字解析
            className = className.substring(className.lastIndexOf(".") + 1, className.indexOf("$"));
        } else {
            className = className.substring(className.lastIndexOf(".") + 1, className.length());
        }

        StackTraceElement[] s = Thread.currentThread().getStackTrace();
        for (StackTraceElement value : s) {
            if (value.getMethodName().startsWith("lambda")) {
                next = true;
            }
        }
        if (!next) {
            methodName = s[3].getMethodName();
        } else {
            methodName = s[5].getMethodName();
        }
        int lines = s[3].getLineNumber();

        //生成指向java的字符串 加入到TAG标签里面
        String TAG = "类class" + "(" + className + ".java:" + lines + ")";

        //生成用户想要输出的数据
        StringBuilder temp = new StringBuilder();
        for (Object anOut : out) {
            temp.append(" ").append(anOut).append(",");
        }
        //删除输出数据 最后的 ,  号
        if (out.length != 0) {
            temp.deleteCharAt(temp.length() - 1);
        }

        if (key == null || key.trim().isEmpty()) {
//          System.out.println("类class : " + simpleName + "   方法method :" + methodName + "  line:" + lines + "  输出: " + temp);
            String parameter = "方法method :" + methodName + "  输出: " + temp;
            Log.d(TAG, parameter);
        } else {
//          System.out.println("类class : " + simpleName + "   方法method :" + methodName + "  line:" + lines + "  输出: " + key + " :" + temp);
            String parameter;
            if (out.length == 0) {
                parameter = "方法method :" + methodName + "  输出: " + "\"" + key + "\"";
            } else {
                parameter = "方法method :" + methodName + "  输出: " + "\"" + key + "\"" + " ::" + temp;
            }
            Log.d(TAG, parameter);
        }
    }


    /**
     * 和上面方法功能相同,少了 key
     *
     * @param object 传入Class类型 可以用getClass()得到
     * @param out    动态参数,这里是要输出的数据
     */
    public static void log(Class<?> object, Object... out) {
        if (!BuildConfig.DEBUG) {
            return;
        }
        boolean next = false;//判断是否含有 lambda 表达式
        String methodName;

        String className = object.getName();
        if (className == null || className.isEmpty()) {
            return;
        } else if (className.contains("$")) { //用于内部类的名字解析
            className = className.substring(className.lastIndexOf(".") + 1, className.indexOf("$"));
        } else {
            className = className.substring(className.lastIndexOf(".") + 1, className.length());
        }
        StackTraceElement[] s = Thread.currentThread().getStackTrace();
        for (StackTraceElement value : s) {
            if (value.getMethodName().startsWith("lambda")) {
                next = true;
            }
        }
        if (!next) {
            methodName = s[3].getMethodName();
        } else {
            methodName = s[5].getMethodName();
        }

        //得到代码所在的行数
        int lines = s[3].getLineNumber();

        //生成指向java的字符串 加入到TAG标签里面
        String TAG = "类class" + "(" + className + ".java:" + lines + ")";

        //生成用户想要输出的数据
        StringBuilder temp = new StringBuilder();
        for (Object anOut : out) {
            temp.append(" ").append(anOut).append(",");
        }
        //删除最后的 ,  号
        if (out.length != 0) {
            temp.deleteCharAt(temp.length() - 1);
        }
        String parameter = "方法method :" + methodName + "  输出: " + temp;
        Log.d(TAG, parameter);
    }
}

 

转载于:https://www.cnblogs.com/qiangge-python/p/10823396.html

<think>我们面对的需求是:在Python调试,如何在不添打印语句的情况下查看所有变量的值。 根据用户提供的引用,我们可以知道有两种主要方法: 1. 使用print语句和断言(但用户不想手动添打印语句) 2. 使用pdb模块进行调试 用户明确要求不添打印语句,因此我们考虑使用pdb(Python调试器)来实现。 在引用[2]中提到:使用pdb模块调试Python,可以通过命令`p 变量名`来打印变量的值。但是,用户希望查看所有变量的值,而不是一个一个地输入变量名。 因此,我们需要一种方法在pdb中一次性查看所有变量。 解决方案: 1. 在pdb中,可以使用`locals()`或`globals()`函数来查看当前作用域的所有局部变量或全局变量。 在pdb提示符下,输入`p locals()`可以打印当前作用域的所有局部变量及其值。 同样,`p globals()`可以打印全局变量。 2. 另外,也可以使用`dir()`函数来列出当前作用域的所有变量,然后逐个查看,但这样比较麻烦。 3. 还有一种方法是使用`pp`(pretty-print)命令来格式化输出字典,因为`locals()`返回的是一个字典。 具体步骤: a) 在代码中需要调试的地方设置断点(例如,使用`pdb.set_trace()`)。 b) 运行程序,程序会在断点处暂停,进入pdb调试环境。 c) 输入`p locals()`或`pp locals()`(格式化输出)来查看所有局部变量。 但是,用户可能希望有一个更自动化的方式,比如在断点处自动打印所有变量。 我们可以通过自定义一个函数,并在断点处调用该函数来实现。但注意,用户要求不添打印语句,这里我们添的是调试代码,但并不是打印语句,而是调用pdb的功能。不过,严格来说,这仍然需要修改代码。 另一种无需修改代码的方法:使用pdb的命令行调试。 例如,使用命令行启动调试: python -m pdb script.py 然后在需要的候输入命令,但这样需要知道断点位置。 或者,我们可以设置断点,并在断点处执行命令。在pdb中,我们可以使用`commands`命令来设置在断点处自动执行的命令。 例如: (Pdb) break 10 # 在第10行设置断点 (Pdb) commands 1 # 为断点1(假设上面设置的断点编号为1)设置命令 (com) p locals() (com) end 这样,当程序运行到第10行的断点,会自动执行`p locals()`,打印所有局部变量。 但是,这种方法需要事先知道断点位置,并且需要手动输入命令。 为了更便捷,我们可以使用集成开发环境(IDE)的调试功能,比如PyCharm、VSCode等,它们通常提供在断点处查看所有变量的功能,而无需手动添打印语句。 因此,总结有以下几种方法方法一:使用pdb的`locals()`函数 - 在代码中插入`import pdb; pdb.set_trace()`,当程序运行到这一行,会进入pdb调试环境。 - 在pdb提示符下输入`p locals()`或`pp locals()`。 方法二:在pdb中设置断点并自动执行命令 - 使用`python -m pdb script.py`启动调试。 - 设置断点:`break <行号或函数名>` - 使用`commands <断点编号>`来设置自动执行的命令(包括`p locals()`)。 方法三:使用IDE的调试功能(推荐) - 在IDE中设置断点,然后启动调试。 - 在调试过程中,通常有一个“变量”(Variables)窗口,会显示当前作用域的所有变量及其值。 方法四:使用`inspect`模块(但需要编写代码,不符合不添打印语句的要求,不过我们可以考虑在调试后删除) - 在代码中临: import inspect print(inspect.currentframe().f_locals) - 这会在运行到该位置打印所有局部变量。 考虑到用户要求不添打印语句,我们推荐使用pdb或IDE调试器。 因此,我们重点介绍pdb的方法。 详细步骤(方法一): 1. 在需要查看变量的位置插入: import pdb; pdb.set_trace() 2. 运行程序,程序会在该行暂停,进入pdb调试环境。 3. 在pdb提示符下输入: (Pdb) p locals() 或者,为了更美观的打印(使用pprint): (Pdb) from pprint import pprint (Pdb) pprint(locals()) 注意:在pdb中,可以执行任何Python语句,所以我们可以导入pprint模块。 但是,如果变量很多,输出可能会很长。我们可以选择只打印变量名,然后根据需要查看具体变量,或者使用过滤。 另外,也可以使用`whos`命令(类似于MATLAB)?但是标准的pdb并没有`whos`命令。我们可以自己定义一个函数,但这样又需要修改代码。 因此,我们回到用户的需求:查看所有变量值。使用`p locals()`是最直接的方法方法五:使用第三方调试工具,如`ipdb`(提供增强的pdb,支持颜色和标签页等)或`pudb`(基于控制台的全屏调试器),这些工具通常提供更友好的界面。 例如,使用`ipdb`: pip install ipdb 在代码中:import ipdb; ipdb.set_trace() 在ipdb中,可以使用`whos`命令来列出当前作用域的所有变量及其类型和值摘要。 所以,如果用户不介意安装第三方库,ipdb是一个不错的选择。 总结: 根据用户的需求,我们推荐: 1. 如果使用IDE,直接用IDE的调试功能(最方便,无需命令行操作)。 2. 如果使用命令行,可以使用pdb的`p locals()`命令。 3. 或者使用ipdb,它提供了`whos`命令可以更清晰地列出变量。 因此,我们给出以下回答:</think>### Python调试如何不添打印语句查看所有变量值 在Python调试中,不添打印语句查看所有变量值有以下几种高效方法: #### 1. **使用pdb调试器(内置模块)** - 在代码中插入断点: ```python import pdb; pdb.set_trace() # 程序运行到此会暂停 ``` - 调试命令: - `locals()`:查看当前作用域所有局部变量 - `globals()`:查看全局变量 - `p <变量名>`:查看特定变量值 - **查看所有变量**:直接输入`locals()`或`globals()`[^2] ```python (Pdb) locals() # 显示所有局部变量的字典 (Pdb) globals() # 显示所有全局变量 ``` #### 2. **使用IDE内置调试器(推荐)** - **VSCode**: 1. 设置断点 2. 启动调试(F5) 3. 在`变量(Variables)`窗口查看所有变量 - **PyCharm**: 1. 右键点击行号设置断点 2. 调试运行(Shift+F9) 3. 在`Variables`面板查看所有变量值 #### 3. **使用增强版调试器ipdb** ```python pip install ipdb # 安装 ``` - 在代码中插入: ```python import ipdb; ipdb.set_trace() ``` - 调试命令: - `whos`:列出所有变量及其类型/值摘要 - `locals()`/`globals()`:完整变量列表 ```python (ipdb) whos # 清晰表格化展示变量 ``` #### 4. **事后调试(Post-mortem)** ```bash python -m pdb your_script.py # 启动调试 (Pdb) continue # 运行到崩溃点 (Pdb) locals() # 查看崩溃的所有变量 ``` #### 5. **使用`inspect`模块(代码内省)** ```python import inspect def debug_func(): current_frame = inspect.currentframe() print(current_frame.f_locals) # 打印当前作用域所有变量 ``` > **关键优势**:这些方法无需修改业务逻辑代码,避免`print`语句污染,且能动态查看任意刻的变量状态。 --- ### 相关问题 1. 如何在Python调试过程中动态修改变量值? 2. 有哪些方法可以跟踪Python函数的调用栈? 3. 如何配置VSCode实现远程Python调试? 4. Python调试器pdb和ipdb的主要区别是什么? 5. 怎样在Jupyter Notebook中高效调试代码? [^1]: 使用`print`和断言是基础调试手段,但无法满足动态查看所有变量的需求。 [^2]: 通过`locals()`/`globals()`可完整获取变量字典,无需单独打印每个变量。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值