可能是最强大的Python debug工具包!

对于机器学习领域尤其好用!

先上代码:

import torch
import numpy as np
import sys

# 开关 #################################
MAX_LOG = -1  # 0: 不debug, -1: 无限输出
TO_FILE = True  # 是否写入debug.log
PRINT = True  # 是否打印出来
BUGGY = True  # 便捷地debug
# 控制是否打印细节:debug(True/False, xxx, xxx)

# 实现 #################################

debug_count = 1
debug_file = None

if TO_FILE:
    debug_file = open("debug.log", "w")


class ExceptionHook:
    instance = None

    def __call__(self, *args, **kwargs):
        if not BUGGY:
            return
        if self.instance is None:
            from IPython.core import ultratb
            self.instance = ultratb.FormattedTB(mode='Plain',
                                                color_scheme='Linux', call_pdb=1)
        return self.instance(*args, **kwargs)


sys.excepthook = ExceptionHook()


def get_cur_info():
    logging(sys._getframe().f_code.co_filename)  # 当前文件名
    logging(sys._getframe(0).f_code.co_name)  # 当前函数名
    logging(sys._getframe(1).f_code.co_name)  # 调用该函数的函数的名字,如果没有被调用,则返回module
    logging(sys._getframe().f_lineno)  # 当前行号


def logging(*message, end="\n"):
    """同时输出到终端和debug.log"""
    message = " ".join([str(_) for _ in message])
    if debug_file:
        debug_file.write(message + end)
    if PRINT:
        print(f"\033[1;33m{message}\033[0m", end=end)


def info(i, name="", detail=True):
    """递归打印变量"""
    if type(i) == int or type(i) == float:
        logging(name, "num val:", i)
    else:
        try:
            j = float(i)
        except Exception:
            if type(i) == list:
                logging(name, "list size:", len(i),
                        "val:", i if detail else "*")
            elif type(i) == dict:
                logging(name, "dict with keys", list(i.keys()))
                for key in i:
                    logging("    ", end='')
                    info(i[key], key, detail)
            elif type(i) == torch.Tensor:
                logging(name, "Tensor size:", i.shape,
                        "val:", i if detail else "*")
            elif type(i) == np.ndarray:
                logging(name, "ndarray size:", i.shape,
                        "val:", i if detail else "*")
            else:
                logging(name, "unk with val: ", i)
        else:
            logging(name, "num val:", j, type(i))


def debug(*args, **kwargs):
    """debug打印主入口"""
    global debug_count
    global debug_file
    count = 1
    if MAX_LOG != -1 and debug_count >= MAX_LOG:
        if debug_file:
            debug_file.close()
        return
    detail = True
    if args and type(args[0]) is bool:
        detail = args[0]
        args = args[1:]
    keys = list(kwargs.keys())
    logging(
        f"### debug print start, total {len(args) + len(kwargs)} variable: including {keys}")
    for i in args:
        logging(f"{count}.",  end=" ")
        info(i, detail=detail)
        debug_count += 1
        count += 1
    for i in keys:
        logging(f"{count}.", end=" ")
        info(kwargs[i], i, detail=detail)
        count += 1
        debug_count += 1
    logging("-------------------------------------")

使用方法:

准备工作:在需要debug的xxx.py文件同目录下新建debug.py,将以上代码复制进去,再在xxx.py中插入from debug import debug

自动停在出错的那一步(需设置BUGGY = True):当出现Exception,程序不会退出,而是会暂停在出现Exception的那一步。这时你可以使用p var(输出var的值), up(上一步), down(下一步)等控制命令进行调试。

打印变量:还在使用print(var)来查看变量值?试试debug(var)吧!可以将变量值、变量类型、变量的size(对于list、numpy的array、torch的tensor)同步输出在终端(PRINT = True)和debug.log文件中(TO_FILE = True)。

进阶技巧:你可以一次性打印多个变量:debug(var1, var2, var3, …)。如果你想给各个变量命名以更好地区分打印出的各个变量,可以使用debug(name1=var1, name2=var2, …)。对于一些循环程序,你或许只想打印有限次,只需设置 MAX_LOG=想打印的次数 即可。如果你希望只打印变量的size,而不打印变量的内容,可以使用debug(False, var)。

发布者:Vision

朝闻道,夕死可矣

发表评论

Fill in your details below or click an icon to log in:

WordPress.com 徽标

您正在使用您的 WordPress.com 账号评论。 注销 /  更改 )

Google photo

您正在使用您的 Google 账号评论。 注销 /  更改 )

Twitter picture

您正在使用您的 Twitter 账号评论。 注销 /  更改 )

Facebook photo

您正在使用您的 Facebook 账号评论。 注销 /  更改 )

Connecting to %s

%d 博主赞过: