Python 第三方打印库介绍 — LK Logger

lk-logger 是一个增强型的打印库, 它被设计为能直接替换 python 内置的 print 函数, 在此之上提供两个对开发者更友好的功能:

  • 在打印内容时, 同时打印出源码所在文件行号
  • 通过一些预设的标记, 打印具有高亮效果或特定格式的文本
  • 下面的两张图直观地说明 printlk-logger 的打印效果区别:

    安装和使用

    通过 pip 安装, 支持 python 3.8 及以上版本:

    pip install lk-logger
    

    使用方法很简单, 在主入口文件添加下面两行代码, 则全部脚本都会生效:

    # main.py
    
    # add two lines to import & setup lk-logger
    import lk_logger
    lk_logger.setup()
    
    # now it effects
    print('hello world')
    #   ./main.py:8  >  hello world
    

    以上, 几乎就是 lk-logger 的全部用法.

    更多用法

    显示变量名

    import lk_logger
    lk_logger.setup(show_varnames=True)
    #               ^^^^^^^^^^^^^^^^^^
    a = 1
    b = 2
    print(a, b, a + b)
    

    设置 setup 函数传参 show_varnames=True, lk-logger 会检测源代码中的变量名, 伴随值一同打印出来:

    它的效果类似于 print(f'a = {}; b = {}; a + b = {}'.format(a, b, a + b)), 但明显地书写要简洁得多.

    美化来自第三方库的打印

    假设导入的第三方库 (比如 “site-packages” 目录下的第三方包) 也用了 print 代码, lk-logger 会缩写源文件路径, 并以其他颜色高亮显示库名称:

    import lk_logger
    lk_logger.setup(quiet=True, show_varnames=True)
    
    import depsland  # pip install depsland
    # ^ there are some prints in depsland initial time.
    #   let's see the print results.
    print(depsland.__version__)
    

    高亮文本

    下面是一部分常见的高亮效果示例, 完整的语法标记表在后面的 “标记语法” 一节给出.

    import lk_logger
    lk_logger.setup(quiet=True)
    
    print('[red]hello[/] [yellow]world[/]', ':r')
    # ^ notice ':r' mark, we'll explain later.
    
    print(':d', 'divider line')
    
    # verbosities
    print(':v0', 'debug')
    print(':v1', 'info (dimmed)')
    print(':v2', 'info')
    print(':v3', 'success (dimmed)')
    print(':v4', 'success')
    print(':v5', 'warning (dimmed)')
    print(':v6', 'warning')
    print(':v7', 'error (dimmed)')
    print(':v8', 'error')
    

    异常处理

    lk-logger 依赖 rich 库, 后者提供了漂亮的异常信息界面:

    import lk_logger
    lk_logger.setup(quiet=True)
    # try to raise an error
    x = 1 / 0
    

    在 IPython 中使用

    lk-logger 在 ipython 中对效果进行了一些调整, 减少了信息的干扰, 以适应 ipython 的使用场景.

    该功能是自动的, 不需要在代码中额外添加参数.

    计时和计数

    这里会用到 “标记用法”, 关于标记语法会在后续章节详细说明, 下面仅作效果展示:

    import lk_logger
    lk_logger.setup(quiet=True)
    
    print(':d', 'indexing')
    print(':i', 'aaa')
    print(':i', 'bbb')
    print(':i', 'ccc')
    print(':i0', 'reset counter')
    print(':i', 'ddd')
    print(':i', 'eee')
    print(':i', 'fff')
    
    print(':d', 'timing')
    from time import sleep
    sleep(0.1)
    print(':t', '... in a short delay')
    sleep(1)
    print(':t', '... in a little long delay')
    sleep(5)
    print(':t', '... in a long delay')
    

    进阶用法

    反射源码层级

    默认情况下, lk-logger 打印的是当前的源码所在的文件行号. 有时候我们会想打印源码的上一层级 (frame), 以便了解是谁在调用当前模块.

    假设有一个函数叫 “借阅图书”, 当这个函数被调用时, 我们想知道是谁在借阅图书 (也就是打印借阅者所在的文件行号), 可以这样做:

    import lk_logger
    lk_logger.setup(quiet=True, show_varnames=True)
    
    
    def borrow_a_book(username: str, bookname: str) -> None:
        # use ':p' to point to the parent frame
        print(username, bookname, ':p')
    
    
    borrow_a_book('Shawn', 'Python Crash Course')
    
    # after a while...
    
    borrow_a_book('Alice', 'Deep Learning With Python')
    

    将打印输出到其他处理器 (实验性功能)

    import atexit
    import lk_logger
    from lk_logger import parallel_printing
    
    lk_logger.setup(quiet=True)
    
    class MyLogger:
        def __init__(self):
            self._buffer = []
            atexit.register(self.close)
        
        def write(self, msg: str):
            self._buffer.append(msg)
            
        def close(self) -> None:
            with open('log.txt', 'w') as f:
                f.write('\n'.join(self._buffer))
    
    class MyGui:
        def update_ui(self, msg: str) -> None:
            """ send message to GUI log panel. """
            ...
    
    mylogger = MyLogger()
    mygui = MyGui()
    
    with parallel_printing(
        mylogger.write,
        mygui.update_ui,
        inherit=True,  # default True. 
        # ^ change to False to prevent default behavior (i.e. printing to console).
    ):
        print('hello world!')
    

    标记语法

    lk-logger 使用 “标记” 来简单快速地实现一些常用的高亮效果或文本格式化处理.

    所谓的 “标记”, 是指位于 print 函数的第一个或最后一个参数位置的一个 str 类型的文本, 它以冒号开头, 后跟一个或多个字母和数字, 其形式如下:

    print(':i', 'aaa')
    print(':d', 'bbb')
    print(':v2', 'ccc')
    print(':v4t', 'ddd')
    print('eee', ':i')
    ...
    

    完整的标记符号表如下:

    标记 助记词 说明
    :d divider 分割线
    :e exception 异常信息格式化
    :f flush 清空缓存的打印流 (在多线程打印中有效)
    :i index 计数器
    :l long 长文本格式, 美化对象输出格式
    :p parent 父层级反射
    :r rich 富文本格式 (采用 bbcode 高亮语法)
    :s short 短文本格式 (减弱打印效果)
    :t timer 计时器
    :v verbosity 打印等级

    每个标记符号后面都可以跟一个数字, 数字范围 0 ~ 9. 如果不加数字, 则使用默认的数字, 如下表所示:

    标记 说明 备注
    :d0 (默认) 默认风格的分割线 (一条单横线)
    :d1 块状风格的分割线 (多行文本) 未实现
    :e0 (默认) 以 rich 风格美化异常信息
    :e1 :e0 基础上, 额外显示 locals 信息
    :e2 进入 pdb 交互式控制台 未实现
    :f0 (默认) 清空缓存的打印流, 将它们输出到控制台
    :f1 清空缓存的打印流, 但不输出到控制台
    (会显示一个 “已跳过多少条待打印信息” 的提示)
    :f2 无视缓存的打印流, 优先打印当前信息
    (缓存不会被清空)
    未来可能移除此项
    :i0 重置计数器
    :i1 (默认) 智能计数, 会在合适的作用域开始计数和自动重置计数
    :i2 行计数器, 每次调用计数 +1
    :i3 全局计数器, 每次调用计数 +1
    :l0 (默认) 长文本格式, 美化对象输出格式
    :l1 尽可能以可读的方式展示对象, 对一些 object 对象效果更好
    :p0 反射到自身层级 (也就是源码所在的文件行号)
    :p1 (默认) 反射到上一层级
    :p2, :p3, :p4, … 反射到上上一帧, 上上上一帧, … 谨慎使用, 超过栈深度会报错
    :r0 (默认) 富文本风格 (采用 bbcode 高亮语法)
    :r1 打印 rich 对象, 例如 rich.panel.Panel 实例
    :r2 以合适的 rich 风格打印对象, 目前仅支持符合特定格式的 str, dict, list
    :s0 (默认) 短文本格式 (减弱打印效果)
    :s1 进一步减弱打印效果, 使其几乎与内置的 print 效果一致
    :s2 完全使用内置的 print 来处理打印
    :t0 重置计时器
    :t1 (默认) 计时 (打印到当前为止的时间戳)
    :t2 临时计时器, 局部计时器 待重构
    :v0 (默认) 调试信息 (灰色高亮)
    :v1 负面提示信息 (紫色)
    :v2 正面提示信息, 或无倾向的提示信息 (蓝色)
    :v3 成功信息 (弱提醒) (暗绿色)
    :v4 成功信息 (绿色)
    :v5 弱警告 (暗黄色)
    :v6 警告 (黄色)
    :v7 报错 (弱提醒) (暗红色)
    :v8 报错 (红色) 助记: 2, 4, 6, 8 为主; 1, 3, 5, 7 为辅

    作者:Likianta Me

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python 第三方打印库介绍 — LK Logger

    发表回复