プリティプリント

構文の強調表示に加えて、Richはリスト、辞書、セットなどのコンテナをフォーマット(つまり、*プリティプリント*)します。

プリティプリントされた出力の例を見るには、次のコマンドを実行してください

python -m rich.pretty

出力は端末の幅に合わせて変化することに注意してください。

pprintメソッド

pprint()メソッドは、オブジェクトのプリティプリント方法を調整するために使用できる、いくつかの追加の引数を提供します。インポート方法は次のとおりです

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

インデントガイド

Richは、データ構造のインデントレベルを強調するために、*インデントガイド*を描画できます。これにより、より深くネストされた出力をより簡単に読むことができます。pprintメソッドは、デフォルトでインデントガイドを有効にします。この機能を無効にするには、indent_guides=Falseを設定します。

すべて展開

Richはデータ構造の展開には非常に保守的で、各行にできるだけ多くのデータを収めようとします。必要に応じて、expand_all=Trueを設定することで、Richにすべてのデータ構造を完全に展開するように指示できます。次に例を示します

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

プリティ出力の切り詰め

非常に長いデータ構造は読みづらい場合があり、目的のデータを見つけるために端末で複数のページをスクロールする必要がある場合があります。Richは、端末を埋め尽くすことなく概要を示すために、コンテナと長い文字列を切り詰めることができます。

max_length引数を整数に設定すると、Richは指定された数の要素を超えるコンテナを切り詰めます。データが切り詰められた場合、Richは省略記号...と表示されていない要素の数を表示します。

次に例を示します

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

max_string引数を整数に設定すると、Richはその長さよりも長い文字列を切り詰めます。切り詰められた文字列には、表示されていない文字数が追加されます。次に例を示します

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

プリティレンダラブル

Richは、プリティプリントされたデータを別のレンダラブルに挿入するために使用できるPrettyクラスを提供しています。

次の例は、単純なパネル内にプリティプリントされたデータを表示しています

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

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

プリティフォーマットを調整するためのオプションは多数あります。詳細はPrettyリファレンスを参照してください。

Rich Reprプロトコル

Richはあらゆる出力を構文強調表示できますが、フォーマットは組み込みコンテナ、データクラス、およびattrsライブラリによって生成されたオブジェクトなど、Richが認識している他のオブジェクトに制限されます。カスタムオブジェクトにRichフォーマット機能を追加するには、*rich 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はコンテナdictのフォーマット方法を知っていますが、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フォーマットを有効にするには、任意のクラスに__rich_repr__メソッドを追加できます。このメソッドは、タプルの反復可能オブジェクトを返す必要があります。タプルのリストを返すこともできますが、*ジェネレーター*にするyieldキーワードで表現する方が簡単です。

各タプルは、出力の要素を指定します。

  • yield valueは、位置引数を生成します。

  • yield name, valueは、キーワード引数を生成します。

  • yield name, value, defaultは、valuedefaultと等しくない*場合*にキーワード引数を生成します。

Nonenameとして使用すると、tupleの位置引数をサポートするために、位置引数としても扱われます。

また、Richに*山かっこ*スタイルのreprを生成するように指示することもできます。これは、オブジェクトのコンストラクターを簡単に再作成する方法がない場合に使用される傾向があります。これを行うには、__rich_repr__メソッドの直後に関数属性"angular"Trueに設定します。例えば

__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_repr__メソッドを追加できることに注意してください。Richがインストールされていない場合、何も壊れません。将来的には、より多くのサードパーティライブラリが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

パラメータの名前が属性と同じであれば、Richはrich reprを自動的に生成できます。

rich reprを自動的にビルドするには、auto()クラスデコレータを使用します。上記のBirdの例は上記のルールに従っているため、厳密には独自の__rich_repr__を実装する必要はありません。次のコードは、同じ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

このページで使用されているコード例については、repr.pyを参照してください。