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
模組的field
函式初始化,初始化程式碼為buffer: List[Segment] = field(default_factory=list)
,dataclasses
是Python
3.7 版本的新引入的模組,field
函式可提供更加靈活的初始化方式,並且該模組中的@dataclass
註解可以為類自動新增__init__
等方法,比較方便extend = self._buffer.extend
這種寫法將list
的extent
函式存到了臨時變數裡,後續直接通過extend
呼叫該函式,比物件名.extend
的方式更簡潔。
下面我們來看render(renderable, render_options)
函式的渲染邏輯,該函式裡會呼叫下面的程式碼
render_iterable = renderable.__rich_console__(self, options)
在函式聲明裡renderable
物件是RenderableType
型別的,但實際上Text
型別的,並且這兩種型別沒有繼承關係,這裡沒太想明白作者為什麼這樣搞。所以,這裡的__rich_console__
函式我們要到text.py
檔案中去找。__rich_console__
函式最終會呼叫Text
物件的render
函式,核心程式碼如下:
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())
呼叫get_style
函式,將格式轉為Style
物件,如:'bold red'轉成Style
物件,然後按照不同的顯示格式進行‘分片’,每個‘片段’構造一個Segment
物件儲存文字及其對應的格式。
get_style
函式會呼叫Style.parse(name)
生成Style
物件,核心程式碼如下
@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_definition
取值為bold red
,分割後生成['bold', 'red']列表,當word
變數等於'bold'時,會執行attributes[style_attributes[word]] = True
語句,執行後attributes
等於{'bold': true}
,它是一個字典。當word
變數等於red
時,執行color=word
語句。最終呼叫導數第二行構造Style
物件,Style
物件最核心的兩個資料形式_attributes
和_color
, 前者是int
型別,在我們例子中取值是1,代表'bold',即:粗體。後者代表顏色,即:'red',它是Color
型別的,該類中有個屬性number
也是我們後續要用到的。
下面來看下__rich_console__
函式返回了哪些Segment
物件
可以看到有4個,每一個都有文字及其Style
物件。
回到render(renderable, render_options)
函式,剛剛介紹了__rich_console__
部分,下面還有返回的程式碼, 一起來看看
iter_render = iter(render_iterable)
for render_output in iter_render:
if isinstance(render_output, Segment):
yield render_output
render_iterable
變數是__rich_console__
的返回值,即:4個Segment
物件。遍歷後通過yield
方式返回。該關鍵字用來返回一個迭代器,也可以理解為一個列表。並且yield
返回有個特點,函式返回值只有真正被使用的時候才會執行呼叫函式。
這樣,render(renderable, render_options)
函式就講解完了,返回上一層extend(render(renderable, render_options))
,通過extend
函式將4個Segment
物件儲存到buffer
中,結果如下
然後print
方法就執行完了。看起來已經結束了,然而控制檯列印的程式碼貌似沒有看到。答案就在剛剛的with self
中,with
關鍵字使得執行完程式碼體後,會自動呼叫self
的__exit__
函式。__exit__
函式中呼叫_render_buffer
函式進行最終的輸出,核心程式碼如下
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
split_and_crop_lines
函式是為了適應控制檯的寬度,暫時忽略它。line
變數仍然是剛剛提到的4個Segment
物件,通過for text, style, is_control in line
直接將每個Segment
物件的屬性解出來並賦給text, style, is_control
變數,最終每個style
物件都會呼叫render
方法完成最後的渲染。
render
方法核心程式碼如下
attrs = self._make_ansi_codes(color_system)
rendered = f"\x1b[{attrs}m{text}\x1b[0m" if attrs else text
_make_ansi_codes
函式就不展開了, 其實就是利用上面提到的_attributes
和number
屬性生成標準輸出的能夠識別的格式,返回值attrs
的結果為1;31
,1取自_attributes
代表粗體,31中的1取自number
代表顏色,其他顏色取值是不同的,比如黃色是33,紫色是35。最後通過f-string
格式(新特性)生成rendered
變數,取值為[1;31mWorld[0m
它就是標準輸出流能夠識別的格式。
回到_render_buffer
函式中,呼叫rendered = "".join(output)
將4個渲染後的片段拼在一起,返回。返回後執行的程式碼如下:
text = self._render_buffer()
if text:
self.file.write(text)
self.file
變數的賦值語句為self.file = file or sys.stdout
,由於我們沒有定義file
變數,所以self.file
取值為sys.stdout
。最終的輸出為sys.stdout.write(text)
,至此整個流程就講解完了。如果你理解了上述邏輯,應該可以通過下面程式碼輸出同樣的效果
sys.stdout.write('Hello, \033[1;31mWorld\033[0m!')
所以Rich
做的就是把文字格式準成標準輸出流能識別的格式。
Rich
裡用到的程式碼確實挺新的,能學到很多東西,比直接看書來的快,有興趣的朋友可以自行閱讀。歡迎關注公眾號**渡碼**不斷分享優秀開源專案原始碼分析
相關推薦
Python優秀開源專案Rich原始碼解析
這篇文章對優秀的開源專案Rich的原始碼進行解析,OMG,盤他。為什麼建議閱讀原始碼,有兩個原因,第一,單純學語言很難在實踐中靈活應用,通過閱讀原始碼可以看到每個知識點的運用場景,印象會更深,以後寫程式碼的時候就能應用起來;第二,通過閱讀優秀的開原始碼,可以學習比人的程式碼規範、設計思路;第三,參與到開源社群
Android熱更新開源專案Tinker原始碼解析系列之一:Dex熱更新
Tinker是微信的第一個開源專案,主要用於安卓應用bug的熱修復和功能的迭代。 Tinker github地址:https://github.com/Tencent/tinker 首先向微信致敬,感謝毫無保留的開源出了這麼一款優秀的熱更新專案。
安卓實用優秀開源專案
沉浸式狀態列和沉浸式導航欄 參考資料:https://www.jianshu.com/p/2a884e211a62 開源地址 安卓常用工具類 參考資料: https://blankj.com/2016/07/31/android-utils-code/ 開源地址 動態許可
android面試——開源框架的原始碼解析
1、EventBus (1)通過註解+反射來進行方法的獲取 註解的使用:@Retention(RetentionPolicy.RUNTIME)表示此註解在執行期可知,否則使用CLASS或者SOURCE在執行期間會被丟棄。 通過反射來獲取類和方法:因為對映關係實際上是類對映到所有此類
【機器人學】機器人開源專案KDL原始碼學習:(8)KDL的精髓
首先說一下我的心得: 1. 我認為KDL的精髓是Spatial Vector,結合C++等面向物件的語言可以寫出較好的軟體。 2. 直接閱讀KDL程式碼不適合初學者學習機械臂動力學。 3. 要學習機械臂動力學的話應首先閱讀使用3維向量推導公式的文獻,也就是線速度和角速度獨立分析
【機器人學】機器人開源專案KDL原始碼學習:(4)機械臂逆動力學的牛頓尤拉演算法
機械臂的逆動力學問題可以認為是:已知機械臂各個連桿的關節的運動(關節位移、關節速度和關節加速度),求產生這個加速度響應所需要的力/力矩。KDL提供了兩個求解逆動力學的求解器,其中一個是牛頓尤拉法,這個方法是最簡單和高效的方法。 牛頓尤拉法演算法可以分為三個步驟: step1:
【機器人學】機器人開源專案KDL原始碼學習:(6)笛卡爾空間軌跡規劃、圓弧過渡、姿態插值、梯形速度、pathlength
本文的內容是對另一篇文章(連結)的補充,對Trajectory_example.cpp涉及到的原理作一些簡單的講解,主要內容是: (1)機器人路徑規劃圓弧過渡的原理; (2)機器人路徑規劃梯形波的原理; (3)機器人末端姿態插值的方法(角-軸); (4)KDL
【機器人學】機器人開源專案KDL原始碼學習:(7)examples中的CMakeList.txt檔案解讀
通過學習KDL開源專案的程式碼可以學習CMake構建程式的知識,現簡單介紹一下orocos_kinematics_dynamics-master\orocos_kinematics_dynamics-master\orocos_kdl\examples\CMakeList.txt檔案的指令。
【機器人學】機器人開源專案KDL原始碼學習:(5)KDL如何求解幾何雅克比矩陣
這篇文章試圖說清楚兩件事:1. 幾何雅克比矩陣的本質;2. KDL如何求解機械臂的幾何雅克比矩陣。 一、幾何雅克比矩陣的本質 機械臂的關節空間的速度可以對映到執行器末端在操作空間的速度,這種對映可以通過一個矩陣來描述,就是幾何雅克比矩陣,瞭解雅克比矩陣需要了解這種對映關係的本質,這
【機器人學】機器人開源專案KDL原始碼學習:(3)機器人操作空間路徑規劃(Path Planning)和軌跡規劃(Trajectory Planning)示例
很多同學會把路徑規劃(Path Planning)和軌跡規劃(Trajectory Planning)這兩個概念混淆,路徑規劃只是表示了機械臂末端在操作空間中的幾何資訊,比如從工作臺的一端(A點)沿直線移動到另一端(B點)。而軌跡規劃則加上了時間律,比如它要完成的任務是從A點開始到B點結束,中間
優秀開源庫SDWebImage原始碼淺析
世人都說閱讀原始碼對於功力的提升是十分顯著的, 但是很多的著名開源框架原始碼動輒上萬行, 複雜度實在太高, 這裡只做基礎的分析。 簡潔的介面 首先來介紹一下這個 SDWebImage 這個著名開源框架吧, 這個開源框架的主要作用就是: Asynchronous image downloader w
【轉】如何閱讀大型前端開源專案的原始碼
目前網上有很多「XX原始碼分析」這樣的文章,不過這些文章分析原始碼的範圍有限,有時候講的內容不是讀者最關心的。同時我也注意到,原始碼是在不斷更新的,文章裡寫的原始碼往往已經過時了。因為這些問題,很多同學都喜歡自己看原始碼,自己動手,豐衣足食。 這篇文章主要講的是閱讀大型的前
Vue-cli 命令列工具專案配置原始碼解析
我們都知道vue cli是vue.js 提供一個官方搭建專案命令列工具,可用於快速搭建大型單頁應用。以下是Vue-cli @2.9搭建專案的配置原始碼解析 相關目錄 ├── build │ ├── build.js │ ├── utils.js │ ├── check-versions
向大神看齊: 如何閱讀大型前端開源專案的原始碼(轉)
作者簡介 Daniel 螞蟻金服·資料體驗技術團隊轉自: https://github.com/ProtoTeam/blog/blob/master/201805/3.md目前網上有很多「XX原始碼分析」這樣的文章,不過這些文章分析原始碼的範圍有限,有時候講的內容不是讀者最關
跳一跳python輔助軟體思路及原始碼解析
跳一跳python輔助軟體思路及影象識別原始碼解析 本文將梳理github上最火的wechat_jump_game的實現思路,並解析其影象處理部分原始碼 首先廢話少說先看效果 核心思想 獲取棋子到下一個方塊的中心點的距離 計算觸控式螢幕幕的時間
《Linux高效能伺服器》附帶專案springsnil原始碼解析
原始碼地址 安裝及使用 下載原始碼: git clone https://github.com/liu-jianhao/springsnail.git 然後進入springsnil目錄直接make即可生成可執行檔案 填寫配置檔案,我測試的是網站是網易雲音樂,首先我先看看網
推薦|23個Python爬蟲開源專案程式碼:爬取微信、淘寶、豆瓣、知乎、微博等
今天為大家整理了23個Python爬蟲專案。整理的原因是,爬蟲入門簡單快速,也非常適合新入門的小夥伴培養信心。所有連結指向GitHub,祝大家玩的愉快 1、WechatSogou [1]– 微信公眾號爬蟲。 基於搜狗微信搜尋的微信公眾號爬蟲介面,可以擴充套件成基於搜狗搜尋的爬
關於閱讀開源專案的原始碼,有哪些經驗值得分享?
1、有耐心,忌吃熱豆腐。 有些特別勤快的人,總以為自己能很快閱讀完原始碼,他們之中的有些用量來衡量自己的能幹程度,於是只抓量不抓質。 但是程式碼中涉及到的很多是思想,慢慢領悟其中的精華,這是需要花時間去消化的。 閱讀開源專案的原始碼時,要有耐心,不要浮
Android Studio匯入github優秀開源專案SlidingMenu(簡單方法)
在app 的build.gradel裡面新增 repositories { maven { url "http://jzaccone.github.io/SlidingMenu-aar" } ... } dependencies { compile 'c
GitHub上排名前100的優秀開源專案
主要對當前 GitHub 排名前 100 的專案做一個簡單的簡介, 方便初學者快速瞭解到當前 Objective-C 在 GitHub 的情況. 若有任何疑問可通過微博@甲骨文兒聯絡我 專案名稱 專案資訊 作者是 NSHipster 的博主, iOS 開發界的大神級人