Skill v1.0.1
currentAutomated scan100/100+4 new
version: "1.0.1" name: python description: "Language-specific super-code guidelines for python." risk: safe source: community date_added: "2026-06-16"
Python: Idiomatic Efficiency Reference
Apply only within the requested scope and current project conventions. Preserve behavior, ownership, error handling, accessibility and security; examples are independent fragments, not equivalent rewrites in every context. Verify language/library versions and run relevant checks. Required tests and user-facing progress/results take precedence over brevity rules. Do not install dependencies or delete files merely to follow these examples.
When to Use
- Use this skill when the task matches this description: Language-specific super-code guidelines for python.
Table of Contents
- Comprehensions & Generators
- Unpacking & Destructuring
- Built-ins & stdlib
- Functions & Defaults
- Classes & Dataclasses
- Error Handling
- Type Hints
- Anti-patterns specific to Python
1. Comprehensions & Generators {#comprehensions}
# ❌ Imperative accumulationresult = []for item in items:if item.active:result.append(item.name.upper())# ✅result = [item.name.upper() for item in items if item.active]
# ❌ Dict built in a loopd = {}for k, v in pairs:d[k] = v# ✅d = dict(pairs)# ord = {k: v for k, v in pairs}
# ❌ Generator converted to list unnecessarilytotal = sum(list(x * 2 for x in nums))# ✅ — generator expression works directly in sum()total = sum(x * 2 for x in nums)
Use generator expressions (not list comprehensions) when the result is consumed once and not stored.
2. Unpacking & Destructuring {#unpacking}
# ❌ Index accessfirst = items[0]rest = items[1:]# ✅first, *rest = items
# ❌ Temporary variable for swaptmp = aa = bb = tmp# ✅a, b = b, a
# ❌ items() with separate indexingfor i in range(len(items)):print(i, items[i])# ✅for i, item in enumerate(items):print(i, item)
# ❌ zip with separate indexfor i in range(len(a)):process(a[i], b[i])# ✅for x, y in zip(a, b, strict=True): # Python 3.10+; fail if lengths differprocess(x, y)
3. Built-ins & stdlib {#builtins}
# ❌ Manual max searchmax_val = items[0]for item in items[1:]:if item > max_val:max_val = item# ✅max_val = max(items)
# ❌ Manual groupingfrom collections import defaultdictgroups = defaultdict(list)for item in items:groups[item.category].append(item)# ✅ — same thing, just be explicit about defaultdict; it IS the right tool# (this example is already correct — don't replace defaultdict with a loop)
# ❌ Manual sentinel for dict defaultif key in d:val = d[key]else:val = default# ✅val = d.get(key, default)
# ❌ Rolling your own countercounts = {}for item in items:counts[item] = counts.get(item, 0) + 1# ✅from collections import Countercounts = Counter(items)
Use `itertools` (chain, islice, groupby, product) before writing nested loops for combinatorial or streaming logic.
4. Functions & Defaults {#functions}
# ❌ Mutable default argument (bug, not just style)def append_to(item, lst=[]):lst.append(item)return lst# ✅def append_to(item, lst=None):if lst is None:lst = []lst.append(item)return lst
# ❌ Positional args for everything when keyword clarity helpscreate_user("Alice", True, False, 30)# ✅ — use keyword args at call site for boolean/ambiguous paramscreate_user("Alice", is_admin=True, is_active=False, age=30)
# ❌ Long function doing multiple thingsdef process_and_save(data):# 40 lines of transform# 20 lines of DB write...# ✅ — split only if each part is reused OR independently testabledef _transform(data): ...def _save(record): ...def process_and_save(data): _save(_transform(data))
5. Classes & Dataclasses {#classes}
# ❌ Manual __init__ for data holdersclass Point:def __init__(self, x, y):self.x = xself.y = y# ✅from dataclasses import dataclass@dataclassclass Point:x: floaty: float
# ❌ Class just to hold a namespace of functionsclass MathUtils:@staticmethoddef add(a, b): return a + b# ✅ — module-level functions; classes for state + behaviordef add(a, b): return a + b
# ❌ __repr__ written manually when dataclass gives it free# (see above — use @dataclass)
Use `@dataclass(frozen=True)` for immutable value objects. Use `NamedTuple` when you need tuple unpacking.
6. Error Handling {#errors}
# ❌ Bare excepttry:risky()except:pass# ✅ — catch the specific exception; don't swallow silentlytry:risky()except ValueError as e:logger.warning("Invalid value: %s", e)
# ❌ LBYL (look before you leap) when EAFP is cleanerif os.path.exists(path):with open(path) as f:data = f.read()# ✅ (EAFP)try:with open(path) as f:data = f.read()except FileNotFoundError:data = None
# ❌ Re-raising with raise e (adds a re-raise frame)except Exception as e:raise e# ✅except Exception:raise # bare raise preserves original traceback
7. Type Hints {#types}
# ❌ Overly verbose Union syntax (Python <3.10 style in new code)from typing import Optional, Uniondef f(x: Optional[int]) -> Union[str, None]: ...# ✅ (Python 3.10+)def f(x: int | None) -> str | None: ...
# ❌ Any where a TypeVar or Protocol would be informativefrom typing import Anydef first(lst: list[Any]) -> Any: ...# ✅from typing import TypeVarT = TypeVar("T")def first(lst: list[T]) -> T: ...
Don't add type hints to every local variable — annotate function signatures and class fields; leave obvious locals inferred.
8. Anti-patterns specific to Python {#antipatterns}
| Anti-pattern | Preferred | |
|---|---|---|
len(lst) == 0 | not lst | |
if x == True: | if x: | |
if x == None: | if x is None: | |
range(len(lst)) for iteration | enumerate(lst) | |
| String concatenation in a loop | "".join(parts) | |
import * | explicit imports | |
Catching Exception to log and re-raise | bare raise or let it propagate | |
print() for debug output | logging.debug() | |
os.path.join (Python 3.4+) | pathlib.Path / "subpath" | |
Manual __eq__ + __hash__ on value objects | @dataclass(eq=True, frozen=True) |
Limitations
- These are language-specific guidelines and do not cover overall architectural decisions.
- Over-compression might reduce readability; apply judgement.