Python: Idiomatic Efficiency Reference

← Back to skills

1. [Comprehensions & Generators](#comprehensions) 2. [Unpacking & Destructuring](#unpacking) 3. [Built-ins & stdlib](#builtins) 4. [Functions & Defaults](#functions) 5. [Classes & Dataclasses](#classes) 6. [Error Handling](#errors) 7. [Type Hints](#types) 8. [Anti-patterns specific to Python](#antipatterns)

Category: General & Miscellaneous
Repo: antigravity-awesome-skills
Path: skills/super-code/python/SKILL.md
Updated: 6/18/2026, 7:42:54 AM

AI Summary

1. [Comprehensions & Generators](#comprehensions) 2. [Unpacking & Destructuring](#unpacking) 3. [Built-ins & stdlib](#builtins) 4. [Functions & Defaults](#functions) 5. [Classes & Dataclasses](#classes) 6. [Error Handling](#errors) 7. [Type Hints](#types) 8. [Anti-patterns specific to Python](#antipatterns). It is useful for general automation, multi-purpose workflows, cross-disciplinary tasks, and utility skills. Source: antigravity-awesome-skills (skills/super-code/python/SKILL.md).

Python: Idiomatic Efficiency Reference

Table of Contents

  1. Comprehensions & Generators
  2. Unpacking & Destructuring
  3. Built-ins & stdlib
  4. Functions & Defaults
  5. Classes & Dataclasses
  6. Error Handling
  7. Type Hints
  8. Anti-patterns specific to Python

1. Comprehensions & Generators {#comprehensions}

# ❌ Imperative accumulation
result = []
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 loop
d = {}
for k, v in pairs:
    d[k] = v

# ✅
d = dict(pairs)
# or
d = {k: v for k, v in pairs}
# ❌ Generator converted to list unnecessarily
total = 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 access
first = items[0]
rest = items[1:]

# ✅
first, *rest = items
# ❌ Temporary variable for swap
tmp = a
a = b
b = tmp

# ✅
a, b = b, a
# ❌ items() with separate indexing
for i in range(len(items)):
    print(i, items[i])

# ✅
for i, item in enumerate(items):
    print(i, item)
# ❌ zip with separate index
for i in range(len(a)):
    process(a[i], b[i])

# ✅
for x, y in zip(a, b):
    process(x, y)

3. Built-ins & stdlib {#builtins}

# ❌ Manual max search
max_val = items[0]
for item in items[1:]:
    if item > max_val:
        max_val = item

# ✅
max_val = max(items)
# ❌ Manual grouping
from collections import defaultdict
groups = 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 default
if key in d:
    val = d[key]
else:
    val = default

# ✅
val = d.get(key, default)
# ❌ Rolling your own counter
counts = {}
for item in items:
    counts[item] = counts.get(item, 0) + 1

# ✅
from collections import Counter
counts = 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 helps
create_user("Alice", True, False, 30)

# ✅ — use keyword args at call site for boolean/ambiguous params
create_user("Alice", is_admin=True, is_active=False, age=30)
# ❌ Long function doing multiple things
def process_and_save(data):
    # 40 lines of transform
    # 20 lines of DB write
    ...

# ✅ — split only if each part is reused OR independently testable
def _transform(data): ...
def _save(record): ...
def process_and_save(data): _save(_transform(data))

5. Classes & Dataclasses {#classes}

# ❌ Manual __init__ for data holders
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

# ✅
from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float
# ❌ Class just to hold a namespace of functions
class MathUtils:
    @staticmethod
    def add(a, b): return a + b

# ✅ — module-level functions; classes for state + behavior
def 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 except
try:
    risky()
except:
    pass

# ✅ — catch the specific exception; don't swallow silently
try:
    risky()
except ValueError as e:
    logger.warning("Invalid value: %s", e)
# ❌ LBYL (look before you leap) when EAFP is cleaner
if 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 (loses traceback)
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, Union
def 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 informative
from typing import Any
def first(lst: list[Any]) -> Any: ...

# ✅
from typing import TypeVar
T = 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-patternPreferred
len(lst) == 0not lst
if x == True:if x:
if x == None:if x is None:
range(len(lst)) for iterationenumerate(lst)
String concatenation in a loop"".join(parts)
import *explicit imports
Catching Exception to log and re-raisebare raise or let it propagate
print() for debug outputlogging.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.

Related skills