漂亮的印刷¶

发布时间 2023-09-13 12:49:43作者: linux星

除了语法突出显示之外,Rich 还将格式化(即漂亮的打印)容器,例如列表、字典和集合。

运行以下命令以查看漂亮的打印输出示例:

python -m rich.pretty

注意输出将如何变化以适应端子宽度。

打印方式

该方法提供了更多参数,可用于调整对象的打印方式。以下是导入它的方法:

>>> from rich.pretty import pprint
>>> pprint(locals())

缩进参考线

Rich 可以绘制缩进参考线来突出显示数据结构的缩进级别。这些可以更轻松地阅读更深入嵌套的输出。默认情况下,pprint 方法启用缩进参考线。您可以设置为禁用此功能。indent_guides=False

全部展开

Rich 对扩展数据结构非常保守,并将尝试尽可能多地适应每一行。如果您愿意,可以告诉 Rich 通过设置 来完全展开所有数据结构。下面是一个示例:expand_all=True

>>> pprint(["eggs", "ham"], expand_all=True)

截断漂亮的输出

很长的数据结构可能难以阅读,您可能会发现自己在终端中滚动浏览多个页面以查找您感兴趣的数据。Rich 可以截断容器和长字符串,为您提供概览,而不会淹没您的终端。

如果将参数设置为整数,则 Rich 将截断元素数超过给定数量的容器。如果数据被截断,Rich 将显示省略号和未显示的元素数。max_length...

下面是一个示例:

>>> pprint(locals(), max_length=2)

如果将参数设置为整数,则 Rich 将截断超过该长度的字符串。截断的字符串将附加尚未显示的字符数。下面是一个示例:max_string

>>> pprint("Where there is a Will, there is a Way", max_string=21)

相当可渲染

Rich 提供了一个类,您可以使用该类将漂亮的打印数据插入到另一个可渲染对象中。

下面的示例在一个简单的面板中显示漂亮的打印数据:

from rich import print
from rich.pretty import Pretty
from rich.panel import Panel

pretty = Pretty(locals())
panel = Panel(pretty)
print(panel)

有大量选项可以调整漂亮的格式,有关详细信息,请参阅参考。

丰富的代表协议

Rich 能够在语法上突出显示任何输出,但格式仅限于内置容器、数据类和 Rich 知道的其他对象,例如 attrs 库生成的对象。若要将丰富格式设置功能添加到自定义对象,可以实现丰富 repr 协议

运行以下命令以查看 Rich repr 协议可以生成的内容的示例:

python -m rich.repr

首先,让我们看一个可能从 Rich repr 中受益的类:

class Bird:
    def __init__(self, name, eats=None, fly=True, extinct=False):
        self.name = name
        self.eats = list(eats) if eats else []
        self.fly = fly
        self.extinct = extinct

    def __repr__(self):
        return f"Bird({self.name!r}, eats={self.eats!r}, fly={self.fly!r}, extinct={self.extinct!r})"

BIRDS = {
    "gull": Bird("gull", eats=["fish", "chips", "ice cream", "sausage rolls"]),
    "penguin": Bird("penguin", eats=["fish"], fly=False),
    "dodo": Bird("dodo", eats=["fruit"], fly=False, extinct=True)
}
print(BIRDS)

此脚本的结果将是:

{'gull': Bird('gull', eats=['fish', 'chips', 'ice cream', 'sausage rolls'], fly=True, extinct=False), 'penguin': Bird('penguin', eats=['fish'], fly=False, extinct=False), 'dodo': Bird('dodo', eats=['fruit'], fly=False, extinct=True)}

输出足够长,可以换行到下一行,这可能会使其难以阅读。repr 字符串内容丰富,但有点冗长,因为它们包含默认参数。如果我们用 Rich 打印它,情况会有所改善:

{
    'gull': Bird('gull', eats=['fish', 'chips', 'ice cream', 'sausage rolls'],
fly=True, extinct=False),
    'penguin': Bird('penguin', eats=['fish'], fly=False, extinct=False),
    'dodo': Bird('dodo', eats=['fruit'], fly=False, extinct=True)
}

Rich 知道如何格式化容器字典,但 repr 字符串仍然很冗长,并且输出有一些包装(假设一个 80 个字符的终端)。

我们可以通过添加以下方法来解决这两个问题:__rich_repr__

def __rich_repr__(self):
    yield self.name
    yield "eats", self.eats
    yield "fly", self.fly, True
    yield "extinct", self.extinct, False

现在,如果我们使用 Rich 打印相同的对象,我们将看到以下内容:

{
    'gull': Bird(
        'gull',
        eats=['fish', 'chips', 'ice cream', 'sausage rolls']
    ),
    'penguin': Bird('penguin', eats=['fish'], fly=False),
    'dodo': Bird('dodo', eats=['fruit'], fly=False, extinct=True)
}

默认参数已被省略,输出的格式很好。即使终端中的空间较小,或者我们的对象是深度嵌套数据结构的一部分,输出仍然可读:

{
    'gull': Bird(
        'gull',
        eats=[
            'fish',
            'chips',
            'ice cream',
            'sausage rolls'
        ]
    ),
    'penguin': Bird(
        'penguin',
        eats=['fish'],
        fly=False
    ),
    'dodo': Bird(
        'dodo',
        eats=['fruit'],
        fly=False,
        extinct=True
    )
}

可以将方法添加到任何类以启用丰富格式。此方法应返回元组的可迭代对象。您可以返回元组列表,但使用关键字更容易表达,使其成为生成器__rich_repr__yield

每个元组在输出中指定一个元素。

  • yield value将生成一个位置参数。

  • yield name, value将生成关键字参数。

  • yield name, value, default如果不等于,生成关键字参数。valuedefault

如果使用 作为 ,则它也将被视为位置参数,以支持具有位置参数。Nonenametuple

您还可以告诉 Rich 生成 repr 的尖括号样式,这往往用于没有简单方法来重新创建对象的构造函数的情况。为此,请将函数属性设置为紧跟在方法之后。例如:"angular"True__rich_repr__

__rich_repr__.angular = True

这会将 Rich repr 示例的输出更改为以下内容:

{
    'gull': <Bird 'gull' eats=['fish', 'chips', 'ice cream', 'sausage rolls']>,
    'penguin': <Bird 'penguin' eats=['fish'] fly=False>,
    'dodo': <Bird 'dodo' eats=['fruit'] fly=False extinct=True>
}

请注意,可以将方法添加到第三方库,而无需将 Rich 作为依赖项包含在内。如果未安装 Rich,则不会损坏任何内容。希望将来会有更多的第三方库采用 Rich repr 方法。__rich_repr__

打字

如果要键入 Rich repr 方法,可以导入并返回 ,这将有助于捕获逻辑错误:rich.repr.Result

import rich.repr


class Bird:
    def __init__(self, name, eats=None, fly=True, extinct=False):
        self.name = name
        self.eats = list(eats) if eats else []
        self.fly = fly
        self.extinct = extinct

    def __rich_repr__(self) -> rich.repr.Result:
        yield self.name
        yield "eats", self.eats
        yield "fly", self.fly, True
        yield "extinct", self.extinct, False

自动富重复

如果参数的名称与您的属性相同,则 Rich 可以自动生成丰富的 repr。

若要自动生成丰富的 repr,请使用类修饰器。上面的 Bird 示例遵循上述规则,因此我们不需要严格实现自己的 .以下代码将生成相同的 repr:auto()__rich_repr__

import rich.repr

@rich.repr.auto
class Bird:
    def __init__(self, name, eats=None, fly=True, extinct=False):
        self.name = name
        self.eats = list(eats) if eats else []
        self.fly = fly
        self.extinct = extinct


BIRDS = {
    "gull": Bird("gull", eats=["fish", "chips", "ice cream", "sausage rolls"]),
    "penguin": Bird("penguin", eats=["fish"], fly=False),
    "dodo": Bird("dodo", eats=["fruit"], fly=False, extinct=True)
}
from rich import print
print(BIRDS)

请注意,装饰器还将创建一个__repr__,因此即使您不使用 Rich 打印,您也会获得自动生成的 repr。

如果要自动生成角度类型的 repr,请在装饰器上设置:angular=True

@rich.repr.auto(angular=True)
class Bird:
    def __init__(self, name, eats=None, fly=True, extinct=False):
        self.name = name
        self.eats = list(eats) if eats else []
        self.fly = fly
        self.extinct = extinct