Black
DevOpsツール
Black
概要
Blackは、Pythonの「妥協しない」コードフォーマッターです。PEP 8準拠のコードスタイルを自動適用し、フォーマットに関する議論を排除。設定オプションを最小限に抑制し、一貫性のあるコードスタイルを強制的に適用する「Opinionated」なアプローチを採用。2025年版のBlack 25.1.0では新しい安定スタイルが導入され、Unicode文字正規化、型注釈の改善、docstring検出の強化など、より洗練されたフォーマット機能を提供しています。
詳細
Black(ブラック)は、Python Software Foundation(PSF)が管理するPython専用コードフォーマッターで、2018年のリリース以来、Python開発において「コードフォーマットの議論を終わらせる」ツールとして確立されています。2025年版のBlack 25.1.0では、新しい安定スタイル(2025 stable style)が導入され、より洗練されたフォーマット機能を提供します。
主要な特徴
- 妥協しないフォーマット: 設定オプションを意図的に最小化し、一貫性を重視
- PEP 8完全準拠: Pythonの公式スタイルガイドに厳密に従う
- 高速実行: Rustベースの部分的実装により高速処理を実現
- Jupyter Notebook対応: Jupyter環境でのコードセル自動フォーマット
- エディター統合: VS Code、PyCharm、Vim等の主要エディター対応
- CI/CD統合: GitHub Actions、GitLab CI等での自動チェック・修正
- 決定論的出力: 何度実行しても同じ結果、完全な冪等性
- 最小設定: pyproject.tomlでの限定的な設定オプション
2025年新機能
- Unicode文字正規化: 文字列内のUnicodeエスケープ文字の小文字正規化
- 改善されたdocstring検出: docstring認識の一貫性向上
- 型注釈フォーマット強化: 関数パラメータの末尾カンマ自動追加
- case文の最適化: if文ガードの冗長な括弧除去と行長制御
- コメント処理改善:
# fmt: skip
コメント前の空白正規化を停止
メリット・デメリット
メリット
- 設定不要でPython開発チーム全体の即座なスタイル統一
- フォーマットに関する議論とコードレビュー時間の完全排除
- PEP 8準拠による標準的で読みやすいPythonコード生成
- 高速処理により大規模プロジェクトでも実用的な実行時間
- 決定論的出力による安定したフォーマット結果
- Jupyter Notebook統合による科学計算・データサイエンス環境対応
- エディター統合によるリアルタイム自動フォーマット体験
- 最小設定により学習コストの削減とメンテナンス負荷軽減
- CI/CD統合による自動品質保証とコード品質ゲート実現
- Python専用特化による言語仕様に最適化されたフォーマット
デメリット
- カスタマイズ性の極度な制限(意図的設計だが柔軟性に欠ける)
- 既存コードへの適用時の大幅な変更によるdiff増大
- 個人・チームの既存コーディング習慣との強制的な乖離
- 特定のフォーマット要求(企業標準等)への対応困難
- 行長制限(デフォルト88文字)の調整余地限定
- レガシーコードベースでの一括適用時の大量変更リスク
- 一部エディターでの統合設定の複雑さ
- Python専用のため多言語プロジェクトでの統一ツール使用不可
- フォーマット結果への細かい制御が困難
- 過度なOpinion強制による開発者の表現自由度制限
参考ページ
書き方の例
インストールと基本セットアップ
# 基本インストール
pip install black
# Jupyter Notebook対応インストール
pip install "black[jupyter]"
# 特定バージョン指定
pip install black==25.1.0
# 開発依存として追加
pip install --save-dev black
# 詩人の依存管理(Poetry)
poetry add --group dev black
# requirements.txtに追加
echo "black>=25.1.0" >> requirements-dev.txt
# 動作確認
black --version
black --help
基本的な実行方法
# 単一ファイルのフォーマット
black script.py
# ディレクトリ全体のフォーマット
black src/
# 複数パターン指定
black src/ tests/ scripts/
# チェックモード(変更せずに確認)
black --check src/
# 差分表示(変更内容確認)
black --diff src/
# 詳細出力
black --verbose src/
# 静観モード(エラー時のみ出力)
black --quiet src/
# 特定ファイル除外
black src/ --exclude="migrations|__pycache__|\.venv"
# ラインレングス指定
black --line-length 100 src/
# Jupyter Notebook対応
black notebook.ipynb
設定ファイル(pyproject.toml)
# pyproject.toml - Black設定
[tool.black]
line-length = 88 # 行長設定(デフォルト88)
target-version = ['py39', 'py310', 'py311', 'py312'] # 対象Pythonバージョン
include = '\.pyi?$' # 対象ファイルパターン
extend-exclude = '''
# 除外パターン(正規表現)
/(
# ディレクトリ除外
\.eggs
| \.git
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| _build
| buck-out
| build
| dist
| migrations
# ファイル除外
| foo.py
)/
'''
# プレビュー機能有効化
preview = true
# 文字列正規化無効化(シングルクォート維持)
skip-string-normalization = false
# マジックトレーリングカンマ無効化
skip-magic-trailing-comma = false
# 実験的機能
experimental-string-processing = false
# jupyter notebook設定
jupyter = true
エディター統合設定
VS Code設定
// .vscode/settings.json
{
"python.formatting.provider": "black",
"python.formatting.blackArgs": [
"--line-length=88",
"--target-version=py312"
],
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"[python]": {
"editor.defaultFormatter": "ms-python.black-formatter",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
}
}
}
// Black拡張機能設定
{
"black-formatter.args": [
"--line-length=88",
"--preview"
],
"black-formatter.importStrategy": "fromEnvironment"
}
PyCharm設定
# PyCharm External Tool設定
# File → Settings → Tools → External Tools → Add
Name: Black
Description: Black Python formatter
Program: black
Arguments: $FilePath$
Working Directory: $ProjectFileDir$
# またはFile Watcherとして設定
# File Type: Python
# Scope: Project Files
# Program: black
# Arguments: $FilePath$
pre-commit統合
# .pre-commit-config.yaml
repos:
- repo: https://github.com/psf/black-pre-commit-mirror
rev: 25.1.0
hooks:
- id: black
language_version: python3.12
args: [--line-length=88, --target-version=py312]
# Jupyter Notebook対応
- id: black-jupyter
language_version: python3.12
args: [--line-length=88, --target-version=py312]
# その他のhookと組み合わせ
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: ["--profile", "black"]
- repo: https://github.com/pycqa/flake8
rev: 7.0.0
hooks:
- id: flake8
args: [--extend-ignore=E203,W503,E501]
# pre-commit設定
pip install pre-commit
pre-commit install
pre-commit autoupdate
# 手動実行
pre-commit run black --all-files
pre-commit run --all-files
CI/CD統合例
GitHub Actions
# .github/workflows/black.yml
name: Black Code Formatter
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
black:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Black
run: pip install black[jupyter]==25.1.0
- name: Check formatting with Black
run: black --check --diff src/
- name: Format code with Black (if check fails)
if: failure()
run: black src/
- name: Commit formatting changes
if: failure() && github.event_name == 'pull_request'
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
git add -A
git commit -m "Apply Black formatting" -a || exit 0
git push
tox統合
# tox.ini
[tox]
envlist = py39,py310,py311,py312,black,flake8
[testenv:black]
deps = black[jupyter]==25.1.0
commands = black --check --diff src/ tests/
[testenv:black-format]
deps = black[jupyter]==25.1.0
commands = black src/ tests/
# Makefile統合
format:
black src/ tests/
isort src/ tests/
check:
black --check --diff src/ tests/
isort --check-only src/ tests/
flake8 src/ tests/
他ツールとの統合
isortとの連携
# pyproject.toml - isort設定
[tool.isort]
profile = "black" # Blackと互換性のあるプロファイル
line_length = 88
multi_line_output = 3
include_trailing_comma = true
force_grid_wrap = 0
use_parentheses = true
ensure_newline_before_comments = true
flake8との連携
# .flake8 または setup.cfg
[flake8]
max-line-length = 88
extend-ignore =
# Blackと競合するルールを無視
E203, # whitespace before ':'
W503, # line break before binary operator
E501 # line too long (handled by Black)
mypy統合
# pyproject.toml - mypy設定
[tool.mypy]
python_version = "3.12"
strict = true
# Blackでフォーマットされたコードとの互換性
show_error_codes = true
pretty = true
color_output = true
Jupyter Notebook統合
# Jupyter Notebook専用フォーマット
black notebook.ipynb
# 複数ノートブック
black notebooks/
# Jupyter Lab拡張機能インストール
pip install jupyterlab-code-formatter black
# JupyterLab設定
jupyter lab --generate-config
# Jupyter内でのBlack使用
# マジックコマンド
%load_ext lab_black
# セル自動フォーマット
%%black
def poorly_formatted_function(x,y,z):
return x+y+z
# 結果: 自動的にフォーマットされる
def poorly_formatted_function(x, y, z):
return x + y + z
実際のフォーマット例
フォーマット前
# 悪いフォーマットの例
def calculate_total(items,tax_rate=0.1,discount=0):
total=0
for item in items:
price=item.get('price',0)
quantity=item.get('quantity',1)
total+=price*quantity
tax=total*tax_rate
final_total=total+tax-discount
return final_total
class ProductManager:
def __init__(self,products=[]):
self.products=products
def add_product(self,name,price,category='general'):
product={'name':name,'price':price,'category':category}
self.products.append(product)
def get_products_by_category(self,category):
return [p for p in self.products if p['category']==category]
フォーマット後
# Blackによってフォーマット済み
def calculate_total(items, tax_rate=0.1, discount=0):
total = 0
for item in items:
price = item.get("price", 0)
quantity = item.get("quantity", 1)
total += price * quantity
tax = total * tax_rate
final_total = total + tax - discount
return final_total
class ProductManager:
def __init__(self, products=None):
self.products = products or []
def add_product(self, name, price, category="general"):
product = {"name": name, "price": price, "category": category}
self.products.append(product)
def get_products_by_category(self, category):
return [p for p in self.products if p["category"] == category]
高度な設定とワークフロー
# Makefileでの統合例
.PHONY: format check test
format:
black src/ tests/
isort src/ tests/
check:
black --check --diff src/ tests/
isort --check-only --diff src/ tests/
flake8 src/ tests/
mypy src/
test: check
pytest tests/ -v --cov=src/
ci: format test
echo "CI complete"
# 開発用スクリプト
#!/bin/bash
# scripts/format.sh
set -e
echo "Formatting Python code with Black..."
black src/ tests/
echo "Sorting imports with isort..."
isort src/ tests/
echo "Checking with flake8..."
flake8 src/ tests/
echo "Type checking with mypy..."
mypy src/
echo "Running tests..."
pytest tests/
echo "✅ All checks passed!"