Pythonの優れたオープンソースプロジェクトRichソース解析の流れの分析
8980 ワード
この文章は優秀なオープンソースプロジェクト
以下は今日のテーマに入ります。このオープンソース項目の名前は
各種フォーマット
プログレスバー
効果はクールに見えますが、コードを見てみました。作者が使っているのは
まず柔らかい柿を拾って、次のようにします。
出力効果:
単語
まず図を通して大体の流れを見てみます。
簡単に言えば、テキストのフォーマットを標準出力に変換して識別できるフォーマットに出力すればいいです。次にソースコードについて説明します。
上記のコードにはもう一つの
ここでは先ほど述べた 型の変数を返している。 。
次に
4つのテキストと
このように、
その後、
sys.stdout.write('Hello,\033[1;31 mWorld\033[0 m!]
したがって、
ソース:https://github.com/willmcgugan/rich
締め括りをつける
ここでPythonの優れたオープンソースプロジェクトのRichソース解析に関する記事を紹介します。Pythonの優れたオープンソースプロジェクトの内容については、以前の文章を検索してください。または、下記の関連記事を引き続きご覧ください。これからもよろしくお願いします。
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
関数で初期化され、初期化コードはfield
、buffer: List[Segment] = field(default_factory=list)
はdataclasses
3.7バージョンの新たに導入されたモジュールであり、Python
関数はより柔軟な初期化方式を提供することができ、このモジュールのfield
注釈は、クラスの自動追加@dataclass
などの方法であり、比較的便利である__init__
のこのような書き方は、extend = self._buffer.extend
のlist
関数を一時変数に保存し、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
パラメータStyle
はstyle_definition
であり、分割後に「bold」、「red」のリストを生成し、bold red
変数が「bold」に等しい場合はword
文を実行し、実行後attributes[style_attributes[word]] = True
はattributes
に等しく、辞書である。{'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
のキーワードはコードボディを実行した後、自動的にwith
のself
関数を呼び出します。__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
変数を定義していないので、file
はself.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の優れたオープンソースプロジェクトの内容については、以前の文章を検索してください。または、下記の関連記事を引き続きご覧ください。これからもよろしくお願いします。