Pythonの優れたオープンソースプロジェクトRichソース解析の流れの分析


この文章は優秀なオープンソースプロジェクトRichのソースコードを解析し、OMG、ディスク彼。なぜソースコードを読むことを提案しますか?第一に、単纯な言语を学ぶのは难しいですが、実用的なアプリケーションでは、ソースを読むことによって、各知识ポイントの运用シーンを见ることができます。第二に、優秀なオープンソースコードを読むことによって、人間のコード規範、設計構想を学ぶことができます。第三に、オープンソースコミュニティに参加し、より広範な発展の見通しを得る。第四に、面接の項目を追加します。ですから、時間があれば、優秀なソース項目のソースコードをたくさん読むことをお勧めします。
以下は今日のテーマに入ります。このオープンソース項目の名前はRichといいます。住所:https://github.com/willmcgugan/rich 。このプロジェクトはイギリスの古い鉄で開発されました。友好的なのは中国語の文書があります。その役割はコンソールでリッチテキストと精巧な可視化フォーマットを出力することができる(例えば、表、プログレスバー、markdown)。スクリーンショットで感じてください

各種フォーマット

プログレスバー
効果はクールに見えますが、コードを見てみました。作者が使っているのはPython 3.8バージョンで実現されています。多くの新しい特性が分かりませんので、ソースを見ている間に文法の基礎も補っています。以下は例で簡単にRichのソースコードを見てみます。ソースの説明はできるだけ簡潔にして、ソースコードに関わるいくつかの重要な知識点を重点的に説明します。
まず柔らかい柿を拾って、次のようにします。

from rich import print

print('Hello, [bold yellow]World[/bold yellow]!')
 
出力効果:

単語Worldには、太字、赤の色として表示されています。
まず図を通して大体の流れを見てみます。

簡単に言えば、テキストのフォーマットを標準出力に変換して識別できるフォーマットに出力すればいいです。次にソースコードについて説明します。print関数を呼び出すと、最終的なプログラムはconsole.pyファイルのprint関数に移ります。以下のコードを実行します。
self._collect_renderables関数を呼び出して入力した文字列を処理します。フォーマットが必要な部分をマークします。返したrenderables変数はTextリストです。入力は1文字列しかないので、リストのサイズは1です。変数の結果は以下の通りです。
Span(7, 12, 'bold red')は、枠から出るフォーマットが必要な内容である。
上記のコードにはもう一つのwith selfがあります。その役割は後でまた話します。続いてprint関数は下を見る。

ここでは先ほど述べたrenderables変数を巡回して、先にrender関数レンダリング入力のテキストを呼び出して、extend関数を呼び出してrenderが戻ってきた結果をself._bufferリストに追加します。ここにいくつかの知識があります。簡単に話してください。
  • self._bufferは、関数呼び出しであり、@propertyの注釈が加えられているので、呼び出しは、小かっこを使わなくても良い。self._thread_locals.buffer型の
  • 型の変数を返している。
  • List[Segment]変数は、self._thread_locals.bufferモジュールのdataclasses関数で初期化され、初期化コードはfieldbuffer: List[Segment] = field(default_factory=list)dataclasses 3.7バージョンの新たに導入されたモジュールであり、Python関数はより柔軟な初期化方式を提供することができ、このモジュールのfield注釈は、クラスの自動追加@dataclassなどの方法であり、比較的便利である
  • __init__のこのような書き方は、extend = self._buffer.extendlist関数を一時変数に保存し、extentを介して直接に関数を呼び出し、extendの方式よりも簡潔である。
  • .extend関数のレンダリングロジックを見てみます。この関数では次のコードが呼び出されます。
    
    render_iterable = renderable.__rich_console__(self, options)
    関数宣言ではrender(renderable, render_options)オブジェクトはrenderableタイプですが、実際にはRenderableTypeタイプで、この2つのタイプは継承関係がありません。ここでは著者がなぜこのようにしているのかよく分かりません。したがって、ここのText関数は__rich_console__ファイルで探します。text.py関数は最終的に__rich_console__オブジェクトのText関数を呼び出します。コアコードは以下の通りです。
    
    def render(self, console: "Console", end: str = "") -> Iterable["Segment"]:
     style_map = {index: get_style(span.style) for index, span in enumerated_spans}
    
     _Segment = Segment
    
     for (offset, leaving, style_id), (next_offset, _, _) in zip(spans, spans[1:]):
     yield _Segment(text[offset:next_offset], get_current_style())
    render関数を呼び出して、フォーマットをget_styleオブジェクトに変換し、例えば「bold red」をStyleオブジェクトに変換した後、異なる表示形式で「スライス」を行い、各「セグメント」は1つのStyleオブジェクトにテキストとその対応するフォーマットを構築する。Segment関数は、get_styleを呼び出してStyle.parse(name)オブジェクトを生成します。コアコードは以下の通りです。
    
    @lru_cache(maxsize=1024)
    def parse(cls, style_definition: str) -> "Style":
     words = iter(style_definition.split())
     for original_word in words:
     word = original_word.lower()
     if word == "on":
     # ...  
     elif word in style_attributes:
     attributes[style_attributes[word]] = True
     else:
     color = word
     style = Style(color=color, bgcolor=bgcolor, link=link, **attributes)
     return style
    パラメータStylestyle_definitionであり、分割後に「bold」、「red」のリストを生成し、bold red変数が「bold」に等しい場合はword文を実行し、実行後attributes[style_attributes[word]] = Trueattributesに等しく、辞書である。{'bold': true}変数がwordに等しい場合、red文が実行される。最終的には、導関数2行目の構造color=wordオブジェクト、Styleオブジェクトの最も核心となる2つのデータ形式Style_attributes、前者は_colorタイプであり、私たちの例では、値を取るのは1であり、「bold」、すなわち太字である。後者は色を表しています。すなわち、「red」はintタイプです。このクラスには属性があります。Colorも私たちが後で使うものです。
    次にnumberの関数がどの__rich_console__オブジェクトに戻りましたか?

    4つのテキストとSegmentオブジェクトがあります。Style関数に戻ります。render(renderable, render_options)部分を紹介したばかりです。下に戻ってくるコードがあります。一緒に見に来てください。
    
    iter_render = iter(render_iterable)
    for render_output in iter_render:
     if isinstance(render_output, Segment):
     yield render_output
    __rich_console__変数は、render_iterableの戻り値、すなわち、4つの__rich_console__オブジェクトである。巡回した後、Segment方式で戻ります。このキーワードは、1つのローズマリーを返すために使用されます。リストとしても理解できます。また、yieldは、機能の戻り値が本当に使用されている場合にのみ呼び出し関数を実行することができるという特徴がある。
    このように、yield関数は説明済みで、前の階のrender(renderable, render_options)に戻り、extend(render(renderable, render_options))関数によって4つのextendオブジェクトをSegmentに保存した結果、次のようになります。

    その後、buffer方法が実行された。もう終わったようですが、コンソールから印刷されたコードは見られないようです。答えは先ほどのprintにあります。with selfのキーワードはコードボディを実行した後、自動的にwithself関数を呼び出します。__exit__関数で__exit__関数を呼び出して最終的に出力します。コアコードは以下の通りです。
    
    output: List[str] = []
    append = output.append
    for line in Segment.split_and_crop_lines(buffer, self.width, pad=False):
     for text, style, is_control in line:
     if style and not is_control:
      append(
      style.render(
       text,
       color_system=color_system,
       legacy_windows=legacy_windows,
      )
      )
    rendered = "".join(output)
    
    return rendered
    _render_buffer関数は、コンソールの幅に適応するために、一時的に無視される。split_and_crop_lines変数は依然として先ほど述べた4つのlineオブジェクトであり、Segmentを介して各for text, style, is_control in lineオブジェクトの属性を直接解きほぐしてSegment変数に割り当て、最終的には各text, style, is_controlオブジェクトがstyle方法を呼び出して最後のレンダリングを完了する。render方法のコアコードは以下の通りである。
    
    attrs = self._make_ansi_codes(color_system)
    rendered = f"\x1b[{attrs}m{text}\x1b[0m" if attrs else text
    render関数は展開されていません。つまり、上記の_make_ansi_codes_attributesの属性を利用して標準出力の識別可能なフォーマットを生成し、戻り値numberの結果はattrsで、1は1;31から太字を表し、31のうちの1は_attributesから取って色を表しています。最後にnumberフォーマット(新特性)によりf-string変数が生成され、renderedは標準出力ストリームが識別できるフォーマットである。[1;31mWorld[0m関数に戻ると、呼び出し_render_bufferは、4つのレンダリングされたフラグメントをつづり合わせて返します。返却後に実行するコードは以下の通りです。
    
    text = self._render_buffer()
    if text:
     self.file.write(text)
    rendered = "".join(output)変数の割当文はself.fileです。self.file = file or sys.stdout変数を定義していないので、fileself.fileです。最終的な出力はsys.stdoutです。これで全体の流れが説明されました。上記のロジックを理解すれば、下記のコードを通じて同じ効果を出力できるはずです。
    sys.stdout.write('Hello,\033[1;31 mWorld\033[0 m!]
    したがって、sys.stdout.write(text)は、文字フォーマットを標準出力ストリームに準拠して識別できるフォーマットである。Richで使われているコードは確かに新しいです。多くのことを学ぶことができます。直接本を読むより早く、興味のある友達は自分で読むことができます。
    ソース:https://github.com/willmcgugan/rich
    締め括りをつける
    ここでPythonの優れたオープンソースプロジェクトのRichソース解析に関する記事を紹介します。Pythonの優れたオープンソースプロジェクトの内容については、以前の文章を検索してください。または、下記の関連記事を引き続きご覧ください。これからもよろしくお願いします。