Loading...
Loading...
Comprehensive Python programming guidelines based on Google's Python Style Guide. Use when you needs to write Python code, review Python code for style issues, refactor Python code, or provide Python programming guidance. Covers language rules (imports, exceptions, type annotations), style rules (naming conventions, formatting, docstrings), and best practices for clean, maintainable Python code.
npx skill4agent add codingkaiser/kaiser-skills python-style-guideimportfrom pydantic import BaseModel # Third-party: Class import OK
from pathlib import Path # Stdlib: Class import OK
import sound_effects.utils # App: Module import
from myproject import config # App: Module importfrom myproject.utils import heavy_function # App: Avoid direct function import if circular dep risktypingcollections.abc# Standard library
import os
import sys
# Third-party
import numpy as np
import tensorflow as tf
# Application-specific
from myproject.backend import api_utilsexcept:try:
result = risky_operation()
except ValueError as e:
logging.error(f"Invalid value: {e}")
raisetry:
result = risky_operation()
except: # Too broad, hides bugs
passlistdictsettyping.Listfrom typing import Any, UnionNonetype(None)NoneTypedef fetch_data(url: str, timeout: int = 30) -> dict[str, Any]:
"""Fetch data from URL."""
...
def process_items(items: list[str]) -> None:
"""Process a list of items."""
...def foo(a: int, b: list[int] | None = None) -> None:
if b is None:
b = []def foo(a: int, b: list[int] = []) -> None: # Mutable default - WRONG!
b.append(a)None0if not users: # Preferred
if not some_dict:
if value:if len(users) == 0: # Verbose
if users == []:
if value == True: # Never compare to True/False explicitlyresult = [x for x in data if x > 0]
squares = (x**2 for x in range(10))# Too complex
result = [
x.strip().lower() for x in data
if x and len(x) > 5 and not x.startswith('#')
for y in x.split(',') if y
] # Use a regular loop insteadsorted(data, key=lambda x: x.timestamp)def get_timestamp(item):
return item.timestamp
sorted(data, key=get_timestamp)# Aligned with opening delimiter
foo = long_function_name(var_one, var_two,
var_three, var_four)
# Hanging indent (4 spaces)
foo = long_function_name(
var_one, var_two, var_three,
var_four)| Type | Convention | Examples |
|---|---|---|
| Packages/Modules | | |
| Classes | | |
| Functions/Methods | | |
| Constants | | |
| Variables | | |
| Private | | |
ijk__double_leading_and_trailing_underscore__def fetch_smalltable_rows(
table_handle: smalltable.Table,
keys: Sequence[bytes | str],
require_all_keys: bool = False,
) -> Mapping[bytes, tuple[str, ...]]:
"""Fetches rows from a Smalltable.
Retrieves rows pertaining to the given keys from the Table instance
represented by table_handle. String keys will be UTF-8 encoded.
Args:
table_handle: An open smalltable.Table instance.
keys: A sequence of strings representing the key of each table
row to fetch. String keys will be UTF-8 encoded.
require_all_keys: If True, raise ValueError if any key is missing.
Returns:
A dict mapping keys to the corresponding table row data
fetched. Each row is represented as a tuple of strings.
Raises:
IOError: An error occurred accessing the smalltable.
ValueError: A key is missing and require_all_keys is True.
"""
...class SampleClass:
"""Summary of class here.
Longer class information...
Longer class information...
Attributes:
likes_spam: A boolean indicating if we like SPAM or not.
eggs: An integer count of the eggs we have laid.
"""
def __init__(self, likes_spam: bool = False):
"""Initializes the instance based on spam preference.
Args:
likes_spam: Defines if instance exhibits this preference.
"""
self.likes_spam = likes_spam
self.eggs = 0# Block comment explaining the following code.
# Can span multiple lines.
x = x + 1 # Inline comment (use sparingly)x = f"name: {name}; score: {score}"x = "name: %s; score: %d" % (name, score)
x = "name: {}; score: {}".format(name, score)x = "name: " + name + "; score: " + str(score) # Avoid + for formattinglogger.info("Request from {} resulted in {}", ip_address, status_code)logging%pathlibdata = Path("file.txt").read_text()
Path("output.txt").write_text("content")with open("image.png", "rb") as f:
data = f.read()if foo:
bar()if foo: bar() # Avoiddef main():
...
if __name__ == "__main__":
main()class MyClass:
def method(self) -> "MyClass":
return selffrom typing import TypeAlias
ConnectionOptions: TypeAlias = dict[str, str]
Address: TypeAlias = tuple[str, int]
Server: TypeAlias = tuple[Address, ConnectionOptions]from typing import TypeVar
_T = TypeVar("_T") # Good: private, unconstrained
AddableType = TypeVar("AddableType", int, float, str) # Good: descriptivedef get_names(employee_ids: list[int]) -> dict[int, str]:
...def get_names(employee_ids: list) -> dict: # Missing type parameters
...from collections.abc import Mapping, Sequence
from typing import Any, Union
# Use built-in types for containers (Python 3.9+)
def foo(items: list[str]) -> dict[str, int]:
...def handle_response(response: dict) -> str:
match response:
case {"status": "ok", "data": data}:
return f"Success: {data}"
case {"status": "error", "message": msg}:
return f"Error: {msg}"
case {"status": status}:
return f"Unknown status: {status}"
case _:
return "Invalid response"def process(value: int | str | list) -> str:
match value:
case int(n) if n > 0:
return f"Positive int: {n}"
case int(n):
return f"Non-positive int: {n}"
case str(s):
return f"String: {s}"
case [first, *rest]:
return f"List starting with {first}"slots=Truefrom dataclasses import dataclass
@dataclass(slots=True)
class Point:
x: float
y: float
@dataclass(slots=True, frozen=True)
class ImmutableConfig:
host: str
port: int
timeout: float = 30.0from __future__ import annotationsfrom __future__ import annotations
class Node:
def __init__(self, children: list[Node]) -> None: # No quotes needed
self.children = children
def add_child(self, child: Node) -> None:
self.children.append(child)try:
async with asyncio.TaskGroup() as tg:
tg.create_task(task1())
tg.create_task(task2())
except* ValueError as eg:
for exc in eg.exceptions:
logger.error("ValueError: {}", exc)
except* TypeError as eg:
for exc in eg.exceptions:
logger.error("TypeError: {}", exc)class Square:
def __init__(self, side: float):
self._side = side
@property
def area(self) -> float:
return self._side ** 2x = "yes" if condition else "no"from contextlib import contextmanager
@contextmanager
def managed_resource(*args, **kwargs):
resource = acquire_resource(*args, **kwargs)
try:
yield resource
finally:
release_resource(resource)ruffdict = 'something' # noqa: A001__init__.py__init__.py# __init__.py
# This file should be empty# Instead of: from mypackage import MyClass
# Use: from mypackage.core import MyClass| Purpose | Library |
|---|---|
| Data validation/models | |
| Logging | |
| CLI | |
| Testing | |
ruff checkruff format__init__.py