Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when reading or writing Python files (.py, pyproject.toml, requirements.txt).
.claude/skills/aiskillstore-python-best-practices/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-02 | ✗→✓ | ▲ Improved | -13% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 1% | 0% |
| case-10 | ✗→✓ | ▲ Improved | -28% | 0% |
| case-19 | ✗→✓ | ▲ Improved | -35% | 0% |
| case-15 | ✓→✓ | = Same ✓ | 0% | 0% |
Follows type-first, functional, and error handling patterns from CLAUDE.md. This skill covers language-specific idioms only.
Use Python's type system to prevent invalid states at type-check time.
Frozen dataclasses for immutable domain models:
pythonfrom dataclasses import dataclass from datetime import datetime @dataclass(frozen=True) class User: id: str email: str name: str created_at: datetime # Frozen dataclasses are immutable — no accidental mutation
Discriminated unions with Literal:
pythonfrom dataclasses import dataclass from typing import Literal @dataclass class Success: status: Literal["success"] = "success" data: str @dataclass class Failure: status: Literal["error"] = "error" error: Exception RequestState = Success | Failure def handle_state(state: RequestState) -> None: match state: case Success(data=data): render(data) case Failure(error=err): show_error(err)
NewType for domain primitives:
pythonfrom typing import NewType UserId = NewType("UserId", str) OrderId = NewType("OrderId", str) def get_user(user_id: UserId) -> User: # Type checker prevents passing OrderId here ...
Protocol for structural typing:
pythonfrom typing import Protocol class Readable(Protocol): def read(self, n: int = -1) -> bytes: ... def process_input(source: Readable) -> bytes: # Accepts any object with a read() method — no inheritance required return source.read()
Chain exceptions with from err to preserve the original traceback:
pythontry: data = json.loads(raw) except json.JSONDecodeError as err: raise ValueError(f"invalid JSON payload: {err}") from err
Use a module-level logger with %s formatting (deferred string interpolation):
pythonimport logging logger = logging.getLogger("myapp.widgets") def create_widget(name: str) -> Widget: logger.debug("creating widget: %s", name) widget = Widget(name=name) logger.debug("created widget id=%s", widget.id) return widget
For fast type checking, consider ty from Astral (creators of ruff and uv). Written in Rust, significantly faster than mypy or pyright.
bashuvx ty check # run directly, no install needed uvx ty check src/ # check specific path
toml# pyproject.toml [tool.ty] python-version = "3.12"
When to choose:
ty — fastest, good for CI and large codebases (early stage, rapidly evolving)pyright — most complete type inference, VS Code integrationmypy — mature, extensive plugin ecosystem| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-15 | pass→pass | 11,531 | 8,516 | -26% | 1 | 1 | 0% | 2,212 | 2,213 | +0% | 0 | 0 | — |
case-20 | pass→pass | 8,246 | 5,934 | -28% | 1 | 1 | 0% | 1,478 | 1,627 | +10% | 0 | 0 | — |
case-01 | pass→pass | 15,160 | 8,697 | -43% | 1 | 1 | 0% | 2,723 | 2,405 | -12% | 0 | 0 | — |
case-02 | fail→pass | 17,200 | 19,532 | +14% | 1 | 1 | 0% | 3,032 | 2,628 | -13% | 0 | 0 | — |
case-03 | pass→pass | 8,258 | 5,471 | -34% | 1 | 1 | 0% | 1,376 | 1,642 | +19% | 0 | 0 | — |
case-04 | pass→pass | 8,116 | 5,387 | -34% | 1 | 1 | 0% | 1,357 | 1,645 | +21% | 0 | 0 | — |
case-05 | pass→pass | 11,267 | 7,890 | -30% | 1 | 1 | 0% | 1,945 | 2,087 | +7% | 0 | 0 | — |
case-06 | fail→pass | 12,507 | 9,344 | -25% | 1 | 1 | 0% | 2,413 | 2,442 | +1% | 0 | 0 | — |
case-07 | pass→pass | 6,884 | 4,815 | -30% | 1 | 1 | 0% | 1,227 | 1,543 | +26% | 0 | 0 | — |
case-08 | pass→pass | 9,668 | 5,778 | -40% | 1 | 1 | 0% | 1,692 | 1,638 | -3% | 0 | 0 | — |
case-09 | pass→pass | 13,406 | 11,698 | -13% | 1 | 1 | 0% | 2,288 | 2,506 | +10% | 0 | 0 | — |
case-10 | fail→pass | 10,690 | 3,044 | -72% | 1 | 1 | 0% | 1,668 | 1,207 | -28% | 0 | 0 | — |
case-11 | pass→pass | 4,495 | 3,369 | -25% | 1 | 1 | 0% | 758 | 1,261 | +66% | 0 | 0 | — |
case-12 | pass→pass | 11,176 | 6,006 | -46% | 1 | 1 | 0% | 1,980 | 1,752 | -12% | 0 | 0 | — |
case-13 | pass→pass | 11,588 | 7,489 | -35% | 1 | 1 | 0% | 1,975 | 2,069 | +5% | 0 | 0 | — |
case-14 | pass→pass | 9,888 | 4,408 | -55% | 1 | 1 | 0% | 1,674 | 1,464 | -13% | 0 | 0 | — |
case-16 | pass→pass | 6,476 | 3,870 | -40% | 1 | 1 | 0% | 1,195 | 1,355 | +13% | 0 | 0 | — |
case-17 | pass→pass | 6,274 | 2,984 | -52% | 1 | 1 | 0% | 1,146 | 1,251 | +9% | 0 | 0 | — |
case-18 | pass→pass | 9,508 | 6,069 | -36% | 1 | 1 | 0% | 1,617 | 1,864 | +15% | 0 | 0 | — |
case-19 | fail→pass | 9,706 | 2,532 | -74% | 1 | 1 | 0% | 1,662 | 1,082 | -35% | 0 | 0 | — |
case-21 | pass→pass | 6,568 | 5,811 | -12% | 1 | 1 | 0% | 1,154 | 1,706 | +48% | 0 | 0 | — |
case-22 | pass→pass | 8,264 | 7,463 | -10% | 1 | 1 | 0% | 1,595 | 2,113 | +32% | 0 | 0 | — |
case-23 | pass→pass | 11,167 | 4,429 | -60% | 1 | 1 | 0% | 1,921 | 1,447 | -25% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +17 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.