格流水線解析)
Black 代碼格式化器完全指南從安裝配置到源碼級風(fēng)格流水線解析【免費下載鏈接】blackThe uncompromising Python code formatter項目地址: https://gitcode.com/GitHub_Trending/bl/blackBlackThe Uncompromising Code Formatter不妥協(xié)的 Python 代碼格式化器是 PSF 出品的 Python 自動格式化工具。本文以倉庫根目錄的 README.md 為主線覆蓋其設(shè)計哲學(xué)、安裝與用法、風(fēng)格規(guī)則與務(wù)實例外、pyproject.toml配置方式并結(jié)合 src/black/init.py、src/black/mode.py 等源碼深入講解一次格式化背后的實際執(zhí)行流水線。讀完后你可以直接在生產(chǎn)項目中落地 Black并理解它的每個默認(rèn)值從何而來。一、Black 是什么一場關(guān)于格式控制權(quán)的交易README 的開篇就點明了 Black 的核心主張Any color you like.喜歡什么顏色都行。Black是不妥協(xié)的 Python 代碼格式化器。使用它意味著你放棄對手工格式細節(jié)minutiae的控制權(quán)作為交換Black 給你速度、確定性以及免于被pycodestyle反復(fù)嘮叨格式問題的自由從而把時間和精力留給更重要的事情。它的三個關(guān)鍵特性直接寫在 README 中跨項目一致性被 Black 格式化過的代碼在任何項目里讀起來都是一樣的。格式在一段時間后變得透明你可以專注于代碼內(nèi)容本身更小的 diffBlack 以產(chǎn)生盡可能小的 diff 為目標(biāo)從而讓代碼審查code review更快確定性同樣的輸入永遠得到同樣的輸出風(fēng)格爭議在團隊內(nèi)被終結(jié)。源碼印證88 列與只認(rèn) .py的默認(rèn)值Black 的默認(rèn)行為在源碼中集中定義于 src/black/const.pyDEFAULT_LINE_LENGTH 88 DEFAULT_EXCLUDES r/(\.direnv|\.eggs|\.git|\.hg|\.ipynb_checkpoints|\.mypy_cache|\.nox|\.pytest_cache|\.ruff_cache|\.tox|\.svn|\.venv|\.vscode|__pypackages__|_build|buck-out|build|dist|venv)/ DEFAULT_INCLUDES r(\.pyi?|\.ipynb)$這解釋了兩件事為什么 Black 默認(rèn)行寬是 88 而不是 PEP 8 的 7988 是為了兼容 80 列寬編輯器下的 88 字符緩沖區(qū)以及為什么直接對目錄運行black .時.git、.venv、build、虛擬環(huán)境等目錄會被自動跳過、只有.py/.pyi/.ipynb文件會被處理——這些正是 README 強調(diào)的sensible defaults合理默認(rèn)值的源碼出處。二、安裝與基本用法2.1 安裝Black 運行需要Python 3.10見 pyproject.toml 中的requires-python 3.10。安裝方式如下pip install black如果需要格式化 Jupyter Notebook需安裝 jupyter 擴展依賴對應(yīng) pyproject.toml 中[project.optional-dependencies]的jupyter [ipython7.8.0, tokenize-rt3.2.0]pip install black[jupyter]此外如果不想安裝 Python 環(huán)境也可以從最新的 GitHub release 下載 PyInstaller 打包的獨立可執(zhí)行文件README 中給出倉庫的 pyproject.toml 中[tool.cibuildwheel]段落即為這些跨平臺二進制文件的構(gòu)建配置覆蓋 CPython 3.10 的 Linux/Windows/macOS 64 位平臺。2.2 三種調(diào)用方式方式一直接運行腳本最快black {source_file_or_directory}方式二作為 Python 包運行腳本不可用時python -m black {source_file_or_directory}方式三格式化代碼字符串而不觸碰文件$ black --code print ( hello, world ) print(hello, world)命令行參數(shù)入口由 pyproject.toml 中的black black:patched_main[project.scripts]注冊主入口patched_main與main均定義在 src/black/init.py。2.3 Black 是守規(guī)矩的 Unix 工具配合倉庫文檔 docs/usage_and_configuration/the_basics.mdREADME 中直接跑就得到合理結(jié)果的承諾背后有一套明確約定找不到任何可格式化源碼時什么都不做文件名用-表示從標(biāo)準(zhǔn)輸入讀、寫標(biāo)準(zhǔn)輸出所有面向用戶的信息只輸出到stderr退出碼為 0除非發(fā)生內(nèi)部錯誤或某個 CLI 選項要求非零退出這對 CI 集成很重要--check模式會因存在未格式化代碼而返回非零。2.4 安全網(wǎng)AST 校驗與--fastREADME 特別提到一個安全機制作為會拖慢處理的安全措施Black會檢查重新格式化后的代碼仍然能產(chǎn)生與原始代碼在語義上等效的 AST詳見文檔中 Pragmatism 一節(jié)的 AST Before and After Formatting 部分。如果你對自己的代碼有信心、想換取速度可以使用black --fast {source}從源碼結(jié)構(gòu)看這個校驗發(fā)生在format_file_contents/format_file_in_placesrc/black/init.py 起中格式化前對源碼做一次ast.dump格式化后再做一次并比較不一致即報錯并保留原文件——這也是倉庫 CHANGES.md 中大量fix unparseable output / failed Blacks own AST safety check條目存在的原因Black 把輸出必須可解析且語義等價當(dāng)作硬性驗收標(biāo)準(zhǔn)。三、Black 代碼風(fēng)格受限的配置 有限度量的務(wù)實3.1 風(fēng)格總則README 對風(fēng)格的表述可以概括為四條PEP 8 兼容Black 是 PEP 8 兼容的、有主見的opinionated格式化器整文件就地重寫_Black_ reformats entire files in place配置項刻意受限風(fēng)格配置選項被刻意限制、極少新增不參考原有格式它基本不考慮你之前的排版少數(shù)例外見務(wù)實一節(jié)最典型的是 magic trailing comma。這套一行一個表達式、超出行寬就沿括號逐層展開的具體排版規(guī)則在倉庫文檔 docs/the_black_code_style/current_style.md 中有完整示例例如短表達式會被合并回一行# in: j [1, 2, 3] # out: j [1, 2, 3]而超長的函數(shù)簽名會被逐參數(shù)展開閉括號回退縮進且補上尾隨逗號def very_important_function( template: str, *variables, file: os.PathLike, engine: str, header: bool True, debug: bool False, ): ...3.2 穩(wěn)定性策略與務(wù)實PragmatismREADME 明確風(fēng)格變更受Stability Policy約束——Black 已趨于穩(wěn)定不應(yīng)預(yù)期未來出現(xiàn)大規(guī)模格式變化風(fēng)格變更主要是對 bug 報告的響應(yīng)和新 Python 語法的適配。它同時警告提交 issue 之前請先閱讀 Current style 與 Future style 兩份文檔看似 bug 的行為可能是有意設(shè)計。Pragmatism務(wù)實一節(jié)說明Black 早期版本在某些方面是絕對主義的追隨其最初作者的風(fēng)格偏好這在用戶很少時讓實現(xiàn)更簡單作為成熟工具Black 現(xiàn)在會對其一般規(guī)則做有限的例外處理。這些例外在文檔中有專門章節(jié)The Black code style: Pragmatism閱讀它同樣應(yīng)在提 issue 之前進行。3.3 源碼印證一次格式化到底發(fā)生了什么理解整文件重寫 確定性最直觀的方式是看核心流水線。入口函數(shù)format_str定義在 src/black/init.py其文檔字符串本身就給出了標(biāo)準(zhǔn)用法import black print(black.format_str(def f(arg:str)-None:..., modeblack.Mode())) # 輸出: # def f(arg: str ) - None: # ...format_str內(nèi)部委托給_format_str_oncesrc/black/init.py完整調(diào)用鏈為decode_bytes用tokenize.detect_encoding檢測文件頭聲明的編碼識別 LF/CRLF/CR 換行并在輸出時還原避免 Windows 換行被無謂改寫lib2to3_parse用倉庫內(nèi)置的 src/blib2to3lib2to3 的分叉構(gòu)建語法樹這是 Black 不依賴 CPython 解析器版本、從而能解析未來語法的關(guān)鍵目標(biāo)版本檢測若用戶未通過-t指定則調(diào)用detect_target_versions依據(jù)from __future__導(dǎo)入與 src/black/init.py 中g(shù)et_features_used識別到的語言特性f-string、下劃線數(shù)字字面量、海象運算符、match 語句、except*、可變參數(shù)泛型、懶導(dǎo)入等見Feature枚舉與VERSION_TO_FEATURES映射定義在 src/black/mode.py推斷語法兼容的版本集LineGenerator遍歷語法樹生成候選邏輯行src/black/linegen.pyEmptyLineTracker維護函數(shù)/類之間的空行規(guī)則transform_line按Mode中的line_length對每行執(zhí)行括號爆炸bracket splitting等變換強制第二遍format_str中有一段注釋直白的Admittedly ugly邏輯——如果第一遍產(chǎn)生了變化就用第一遍的輸出再格式化一次。原因是可選尾隨逗號在第二遍會變成強制尾隨逗號進而與可選括號產(chǎn)生交互必須跑兩遍才能收斂。這段源碼是理解Black 輸出是確定的固定點的最直接證據(jù)。Mode數(shù)據(jù)類src/black/mode.py是全部風(fēng)格參數(shù)的載體dataclass class Mode: line_length: int DEFAULT_LINE_LENGTH # 默認(rèn) 88 string_normalization: bool True # 默認(rèn)統(tǒng)一雙引號 ... preview: bool False # 預(yù)覽風(fēng)格開關(guān)這解釋了 README風(fēng)格配置選項刻意受限的由來——用戶可調(diào)的旋鈕主要就是line_length、string_normalization對應(yīng) CLI 的-l、-S與少量開關(guān)而非一份任意風(fēng)格表。四、配置pyproject.toml是最主要的面板4.1 README 的原文結(jié)論Black可以從pyproject.toml讀取命令行選項的項目級默認(rèn)值這在為項目指定自定義的--include和--exclude/--force-exclude/--extend-exclude模式時特別有用詳見 The basics: Configuration via a file 與 Usage and Configuration。README 還給出了官方 Pro-tip如果你在想我到底需不需要配置什么——答案是不需要。Black 的全部價值就在于合理默認(rèn)值應(yīng)用這些默認(rèn)值你的代碼就能與眾多其他 Black 項目保持一致。4.2 一份可復(fù)制的真實配置Black 項目自用配置本倉庫的 pyproject.toml 就是一份被 Black 官方注釋過的配置范例可以直接作為模板# NOTE: you have to use single-quoted strings in TOML for regular # expressions. Its the equivalent of r-strings in Python. # Multiline strings are treated as verbose regular expressions by Black. # Use [ ] to denote a significant space character. [tool.black] line-length 88 target-version [py310] include \.pyi?$ extend-exclude /( # The following are specific to Black, you probably dont want those. tests/data/ | profiling/ ) # We use the unstable style for formatting Black itself. If you # want bug-free formatting, you should keep this off. unstable true幾個要點TOML 正則有講究正則必須用單引號字符串等價 Python 的 raw string多行字符串按verbose 正則解析[ ]表示顯著空格——這正是extend-exclude里那段/( ... | ... )能寫多行的原因include/extend-exclude分別對應(yīng) CLI 的同名選項用于覆蓋 src/black/const.py 中的DEFAULT_INCLUDES/DEFAULT_EXCLUDESforce-exclude則連顯式傳入的路徑也跳過適合排除第三方生成的目錄target-version-t選項的文件版如target-version [py311, py312, py313]。它決定 Black 用什么語法解析代碼、以及風(fēng)格細節(jié)——例如只有當(dāng)所有目標(biāo)版本 ≥ py35 時Black 才會在f(a, *args)的*args后加尾隨逗號docs/usage_and_configuration/the_basics.md 中給出了 py34/py35 的對比示例unstable true僅 Black 項目自身使用不穩(wěn)定的預(yù)覽風(fēng)格普通項目若追求無 bug 的穩(wěn)定格式應(yīng)保持該標(biāo)志關(guān)閉。對應(yīng)源碼中Mode的 preview 語義unstable 模式啟用全部預(yù)覽特性見 src/black/mode.py 中__contains__的實現(xiàn)注釋。4.3 其他常用開關(guān)速查與 README 承諾的有限旋鈕一致以下選項在 docs/usage_and_configuration/the_basics.md 中有完整說明均可同時以 CLI 或pyproject.toml形式配置選項作用-h, --help顯示全部命令行選項-c, --code格式化傳入的代碼字符串-l, --line-length行寬默認(rèn) 88-t, --target-version目標(biāo) Python 版本可多次給出--pyi/--ipynb強制按 stub / Notebook 處理輸入管道輸入場景-x, --skip-source-first-line跳過源碼第一行-S, --skip-string-normalization保留字符串原樣默認(rèn)統(tǒng)一為雙引號并規(guī)范化前綴-C, --skip-magic-trailing-comma忽略魔法尾隨逗號默認(rèn)會把你已有的尾隨逗號當(dāng)作請保持逐行展開的信號--preview啟用下一大版本可能并入主功能、但可能有破壞性的風(fēng)格變更--fast關(guān)閉 AST 前后比對安全校驗換取速度--line-ranges只格式化指定行范圍配合lines參數(shù)走 src/black/init.py 的sanitized_lines/adjusted_lines路徑五、跳過格式化的三種注釋指令雖然 README 正文未展開但作為以指定文檔為主體、文檔生態(tài)為輔佐的一環(huán)docs/usage_and_configuration/the_basics.md 定義了與放棄格式控制權(quán)直接對沖的逃生艙屬于 README 承諾的基本用法范疇# fmt: skip跳過該行可與其他 pragma 混排# fmt: skip # pylint # noqa或分號列表形式# fmt: off/# fmt: on關(guān)閉/開啟區(qū)間格式化兩者必須處于同一縮進層級、同一代碼塊內(nèi)兼容 YAPF 的# yapf: disable/enable塊注釋。六、社區(qū)采用與口碑README 的 Used by 一節(jié)列出了信任 Black 的知名開源項目pytest、tox、Pyramid、Django、Django Channels、Hypothesis、attrs、SQLAlchemy、Poetry、PyPA 系列應(yīng)用Warehouse、Bandersnatch、Pipenv、virtualenv、pandas、Pillow、Twisted、LocalStack、Datadog Agent 全部集成、Home Assistant、Zulip、Kedro、OpenOA、FLORIS、ORBIT、WOMBAT 等以及使用它的組織Dropbox、KeepTruckin、Lyft、Mozilla、Quora、Duolingo、QuantumBlack、Tesla、Archer Aviation。README 同時收錄了幾位知名開發(fā)者的評價Testimonials其中 SQLAlchemy 作者 Mike Bayer 稱其為整個編程生涯中帶來的生產(chǎn)力提升最大的單一工具重構(gòu)時的擊鍵量降到原來的約 1%attrs 作者、Twisted 核心開發(fā)者 Hynek Schlawack 寫道一個不爛的自動格式化器就是我全部的圣誕愿望requests 作者 Kenneth Reitz 則說它大幅改善了我們代碼的格式化。測試與 CI 基礎(chǔ)設(shè)施README 還提到 Black 擁有全面的測試套件、高效的并行測試以及自研的并行 CI 運行器倉庫中 tests/test_black.py、tests/data/cases/ 下數(shù)百個輸入/輸出成對的用例文件如 tests/data/cases/comments.py、tests/data/cases/torture.py就是穩(wěn)定性承諾的具體載體——每個歷史 bug 修復(fù)都沉淀為一個回歸用例。七、展示你的風(fēng)格README 徽章在自己的項目 README 中聲明使用了 Black是 README 給出的官方做法。Markdown 形式[](https://github.com/psf/black)RST 形式用于 README.rst.. image:: https://img.shields.io/badge/code%20style-black-000000.svg :target: https://github.com/psf/black八、許可、貢獻與周邊文檔LicenseMIT見 LICENSEChange log更新日志較長獨立存放于 CHANGES.md當(dāng)前共 2000 余行按 Stable style / Preview style 等分類記錄每次風(fēng)格與行為變更Authors作者列表同樣獨立存放見 AUTHORS.mdContributing貢獻入門見 docs/contributing/the_basics.md貢獻流程見 docs/contributing/index.mdCode of Conduct遵循 Python 社區(qū)行為準(zhǔn)則README 結(jié)尾還按項目幽默傳統(tǒng)補了一句如果實在需要打某人請邊跳舞邊用魚打。九、總結(jié)為什么這套設(shè)計值得借鑒從 README.md 到源碼Black 的工程決策可以濃縮為三點默認(rèn)值即產(chǎn)品88 列行寬src/black/const.py、自動排除虛擬環(huán)境與構(gòu)建目錄、按語法特性自動探測目標(biāo)版本src/black/mode.py 的VERSION_TO_FEATURES讓零配置成為真實可用的狀態(tài)而非營銷話術(shù)確定性與安全性雙保險兩遍格式化收斂src/black/init.py保證固定點輸出AST 前后比對保證輸出可解析、語義等價--fast留給愿意自己承擔(dān)風(fēng)險的場景變更治理穩(wěn)定性策略 按 Stable/Preview 雙通道發(fā)布風(fēng)格變更CHANGES.md配合# fmt: skip/off逃生艙把工具替你格式化與必要時你說了算的邊界劃得清清楚楚?!久赓M下載鏈接】blackThe uncompromising Python code formatter項目地址: https://gitcode.com/GitHub_Trending/bl/black創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考