Skip to main content

Python Cheatsheet — 100+ Idiomatic Snippets with Pitfalls, Async, and Type Hints

Python cheat sheet — 100+ idiomatic Python snippets for string, list, dict, file, async, with real examples.

  • Runs locally
  • Category Developer & DevOps
  • Best for Formatting, validating, shrinking, or inspecting code-adjacent text.
102 snippets
Basics (7)

Variable assignment & multiple assignment

x = 42
name = "Lei"
a, b, c = 1, 2, 3
x, y = y, x   # swap, no temp variable

Python is dynamically typed — assignment binds a name to an object. Multi-assign on one line; tuple unpack to swap without a temp.

Variants
a = b = c = 0   # chained, all point to same object
first, *rest = [1, 2, 3, 4]   # 1, [2,3,4]

Numeric types: int, float, complex, decimal

n = 10                # int, 任意精度
pi = 3.14             # float, IEEE 754 双精度
z = 2 + 3j            # complex
from decimal import Decimal
price = Decimal("0.1") + Decimal("0.2")   # 精确 0.3

int has no limit (3 ** 200 just works). float is IEEE 754 — 0.1 + 0.2 != 0.3. For money, always use Decimal with string inputs.

Variants
0.1 + 0.2 == 0.3   # False!
from fractions import Fraction; Fraction(1, 3)

bool and truthy / falsy values

bool(0)         # False
bool("")        # False
bool([])        # False
bool(None)      # False
bool("False")   # True (非空字符串都是 True)
bool([False])   # True (列表非空就是 True)

Falsy: 0, 0.0, "", [], {}, set(), None, False. Everything else is truthy — including the string "False" and the list [False].

Variants
if items:  # 比 if len(items) > 0 更地道
x = a or "default"  # a 为假值时取 default

None — the singleton

x = None
if x is None:        # ✅ 推荐
    print("空值")
if x == None:        # 能跑但不地道
    pass

None is a singleton — use `is None` / `is not None`, never `== None`. `is` checks identity, `==` checks equality (and can be overridden).

Type checking with isinstance

isinstance(x, int)             # True if x is int (or bool!)
isinstance(x, (int, float))    # 接受多种类型
type(x) is int                 # 严格相等,不认子类

Use isinstance, not type() == — isinstance respects inheritance. Trap: bool is a subclass of int, so isinstance(True, int) returns True.

Variants
# 排除 bool:isinstance(x, int) and not isinstance(x, bool)

print 与 input

print("a", "b", "c")               # 默认空格分隔
print("a", "b", sep="-")           # "a-b"
print("loading", end="")           # 不换行
print("err msg", file=sys.stderr)  # 打到 stderr
name = input("name: ")             # 读一行(返回 str,不含换行)
age = int(input("age: "))          # 数字记得转

print accepts sep= and end=. input() returns a string (no newline) — convert with int() / float() if you need a number.

range — 区间序列

range(5)            # 0, 1, 2, 3, 4
range(2, 7)         # 2, 3, 4, 5, 6
range(0, 10, 2)     # 0, 2, 4, 6, 8 (步长)
range(10, 0, -1)    # 10, 9, 8, ..., 1 (反向)
list(range(5))      # [0, 1, 2, 3, 4]

range(stop), range(start, stop), range(start, stop, step). It's LAZY — doesn't materialize until you iterate. Stop is exclusive.

String (10)

f-string (the modern way to format)

name = "Lei"
age = 30
s = f"{name} is {age}"            # "Lei is 30"
pi = 3.14159
s = f"{pi:.2f}"                   # "3.14"
n = 1234567
s = f"{n:,}"                      # "1,234,567"
s = f"{name=}, {age=}"            # debug: "name='Lei', age=30"

f-string (3.6+) is the fastest and most readable. Use :.2f for decimals, :, for thousands separator, ={var}= for self-documenting debug prints.

Variants
f"{x:>10}"   # 右对齐宽 10
f"{x:0>5}"   # 左补 0 到 5 位
f"{x:.0%}"   # 百分比

.format() and % — the legacy ways

"Hello, {}!".format("Lei")
"{0} {1} {0}".format("a", "b")    # "a b a"
"{name} is {age}".format(name="Lei", age=30)
"Hello, %s! You are %d." % ("Lei", 30)

.format() and % still work and you will see them in older codebases. Prefer f-string for new code.

split / join — string ↔ list

"a,b,c".split(",")              # ['a', 'b', 'c']
"a b  c".split()                # ['a', 'b', 'c']  (默认按空白切,连续空白当一个)
",".join(["a", "b", "c"])       # "a,b,c"
"\n".join(lines)                # 拼成多行字符串

split() with no args splits on any whitespace AND collapses runs. join() is a STRING method (delimiter on the left), not a list method.

Variants
"a,b,,c".split(",")   # ["a", "b", "", "c"]  (空段保留)
"a,b,c".split(",", 1)   # ["a", "b,c"]  (限制 split 次数)

strip / lstrip / rstrip — 去空白

"  hello  ".strip()           # "hello"
"  hello  ".lstrip()          # "hello  "
"  hello  ".rstrip()          # "  hello"
"xxhelloxx".strip("x")        # "hello"
"https://".rstrip("/")        # "https:"

strip() defaults to whitespace; pass a string to strip ANY character in that set. Trap: rstrip("ing") strips i / n / g in any order, not the substring "ing".

Variants
# Python 3.9+ 才有去前后缀 substring 的方法:
"running".removesuffix("ing")   # "runn"
"running".removeprefix("ru")    # "nning"

replace — 字符串替换

"hello world".replace("world", "Lei")    # "hello Lei"
"a-b-c-d".replace("-", "_", 2)            # "a_b_c-d"  (限制次数)
import re
re.sub(r"\d+", "#", "abc 123 def 456")    # "abc # def #"  (正则替换)

str.replace() does plain substring substitution. For regex, use re.sub(). replace() returns a NEW string — strings are immutable.

startswith / endswith / in

url.startswith("https://")
filename.endswith((".jpg", ".png", ".gif"))   # 元组:满足任一即可
"lei" in "hello lei"                          # 子串包含
"lei" in ["lei", "han"]                       # 列表 in O(n)
"lei" in {"lei", "han"}                       # 集合 in O(1)

startswith / endswith accept a TUPLE — perfect for multi-extension checks. The `in` operator is O(n) on list/string, O(1) on set/dict.

大小写转换 upper / lower / title / casefold

"hello".upper()        # "HELLO"
"HELLO".lower()        # "hello"
"hello world".title()  # "Hello World"
"Hello".casefold()     # "hello"  (比 lower 更激进,能正确处理德语 ß)
"  Hello  ".swapcase() # "  hELLO  "

lower() handles ASCII. casefold() is the case-insensitive comparison standard — handles German ß → ss correctly.

字符串切片与索引

s = "hello"
s[0]        # 'h'
s[-1]       # 'o'
s[1:4]      # "ell"
s[:3]       # "hel"
s[::-1]     # "olleh"  (反转,最骚的一行)
s[::2]      # "hlo"    (步长 2)

Slicing is [start:stop:step], stop exclusive. Negative indexes count from the end. s[::-1] is the canonical reverse one-liner.

编码与解码 encode / decode

"你好".encode("utf-8")              # b'\xe4\xbd\xa0\xe5\xa5\xbd'
b'\xe4\xbd\xa0\xe5\xa5\xbd'.decode("utf-8")  # "你好"
"abc".encode()                      # 默认 UTF-8
# 容错:errors="ignore" / "replace" / "strict"(默认)
b'\xff\xfe'.decode("utf-8", errors="replace")    # "��"

str → bytes via .encode(), bytes → str via .decode(). Default codec is UTF-8. Use errors="replace" or "ignore" to handle malformed bytes without crashing.

多行字符串与 textwrap

s = """第一行
第二行
第三行"""
import textwrap
textwrap.dedent("""
    缩进的多行字符串
    自动去掉前导空格
""")
textwrap.fill("超长一段话", width=40)

Triple-quoted strings preserve newlines. textwrap.dedent strips the common leading whitespace — handy for embedded SQL or templates.

List (12)

append / extend / insert

xs = [1, 2, 3]
xs.append(4)              # [1, 2, 3, 4]   单个元素
xs.extend([5, 6])         # [1, 2, 3, 4, 5, 6]   合并另一个可迭代
xs += [7, 8]              # 等价于 extend
xs.insert(0, 0)           # [0, 1, 2, 3, ...]   指定位置插
xs.append([9, 10])        # [..., [9, 10]]   坑:嵌套了一层

append adds ONE element. extend (or +=) merges an iterable. The classic bug: append([9, 10]) appends the list as a single nested element.

列表切片与切片赋值

xs = [1, 2, 3, 4, 5]
xs[1:4]              # [2, 3, 4]
xs[:]                # [1, 2, 3, 4, 5]   浅拷贝
xs[::-1]             # [5, 4, 3, 2, 1]   反转
xs[1:3] = [20, 30]   # 切片赋值:原地修改
xs[::2] = [10, 30, 50]   # 步长切片赋值,两边长度要一致

Same slice syntax as string. xs[:] is the classic shallow-copy idiom. Slice assignment mutates in place — convenient for batch replaces.

list 推导(List comprehension)

squares = [x * x for x in range(10)]
evens = [x for x in nums if x % 2 == 0]
matrix = [[i * j for j in range(5)] for i in range(5)]
# 双 for 拍平嵌套:
flat = [x for row in matrix for x in row]
# 带 else 的写法(注意 if 位置变了):
labels = ["even" if x % 2 == 0 else "odd" for x in nums]

List comprehensions are Pythonic and usually faster than equivalent for-loops with .append(). Filter goes at the end; ternary goes BEFORE the for clause.

Variants
# 三个以上推导嵌套就拆 for 循环吧,可读性优先

map / filter — 函数式写法

list(map(str, [1, 2, 3]))             # ["1", "2", "3"]
list(map(lambda x: x * 2, nums))      # 不推荐,写成推导更地道
list(filter(lambda x: x > 0, nums))   # 不推荐,写成 [x for x in nums if x > 0]
# 多个可迭代一起:
list(map(lambda a, b: a + b, [1, 2], [10, 20]))   # [11, 22]

map and filter return iterators — wrap in list() to materialize. For one-shot transforms with lambda, list comprehension is more Pythonic.

sorted / sort / key / reverse

sorted([3, 1, 2])                  # [1, 2, 3]   返回新列表
xs.sort()                          # 原地排序,返回 None
sorted(words, key=len)             # 按长度
sorted(users, key=lambda u: u.age) # 按属性
from operator import itemgetter, attrgetter
sorted(rows, key=itemgetter(2))    # 比 lambda 快一点
sorted(xs, reverse=True)           # 降序
# 多列排序:稳定排序,从次要到主要倒着 sort
sorted(rows, key=lambda r: (r[0], -r[1]))   # 第 1 列升、第 2 列降

sorted() returns a new list; .sort() mutates in place and returns None. Use key= for custom criteria; itemgetter is faster than lambda. Sort is stable.

reverse / reversed

xs.reverse()                    # 原地反转,返回 None
list(reversed(xs))              # 返回新列表
xs[::-1]                        # 也是反转,最简洁

.reverse() mutates; reversed() returns an iterator (wrap in list()); xs[::-1] returns a new list and is the shortest.

列表去重(保留顺序)

# 不在乎顺序:
list(set(xs))
# 保留首次出现顺序(3.7+ dict 有序):
list(dict.fromkeys(xs))
# 复杂对象去重(按某 key):
seen = set()
uniq = [x for x in xs if not (x in seen or seen.add(x))]

set() de-dupes but loses order. dict.fromkeys() de-dupes AND preserves first-seen order (works since 3.7 where dicts are ordered).

enumerate — 同时拿索引和值

for i, v in enumerate(items):
    print(i, v)
for i, v in enumerate(items, start=1):    # 从 1 开始
    print(i, v)
# 反例(不要写):
for i in range(len(items)):
    print(i, items[i])      # 不地道

enumerate(seq) yields (index, value) pairs — never write for i in range(len(seq)). start= sets the first index (default 0).

zip — 多个可迭代并行遍历

names = ["Lei", "Han", "Mei"]
ages = [30, 25, 28]
for n, a in zip(names, ages):
    print(n, a)
# 转字典:
d = dict(zip(names, ages))
# 转置矩阵:
list(zip(*matrix))
# 3.10+ strict 模式,长度不一致就抛错:
zip(names, ages, strict=True)

zip pairs up multiple iterables — stops at the shortest by default. zip(*matrix) transposes. Python 3.10+ strict=True errors on length mismatch.

all / any — 列表逻辑判断

all([True, True, True])      # True
all([])                       # True   (空集合默认 True,反直觉)
any([False, False, True])     # True
any([])                       # False
# 实战:
all(x > 0 for x in nums)      # 全部为正
any(s.startswith("error") for s in logs)

all() returns True if every element is truthy (vacuous truth: empty → True). any() returns True if at least one is truthy. Pass a generator for short-circuit.

sum / min / max — 聚合

sum([1, 2, 3])                       # 6
sum([1, 2, 3], 100)                   # 106   (起始值)
max([1, 2, 3])
min(["apple", "banana"], key=len)     # "apple"
max(users, key=lambda u: u.age)
# 3.4+ 提供默认值:
min([], default=0)                    # 不抛错

min/max accept a key= function — common for "longest item" or "youngest user". Both raise ValueError on empty iterable unless you pass default=.

pop / remove / del

xs = [10, 20, 30, 40]
xs.pop()         # 删最后一个,返回 40,xs = [10, 20, 30]
xs.pop(0)        # 删第 0 个,返回 10,xs = [20, 30]
xs.remove(30)    # 按值删第一个匹配的
del xs[0]        # 按索引删(不返回值)
del xs[1:3]      # 按切片删

pop returns the removed element. remove deletes the FIRST match by value (raises if not found). del is a statement, not an expression.

Dict (8)

dict 基本操作

d = {"name": "Lei", "age": 30}
d["name"]              # "Lei"
d["email"] = "x@y.z"   # 加键
del d["age"]           # 删键
"name" in d            # 判键存在
len(d)
list(d.keys()), list(d.values()), list(d.items())

Dicts are hash maps with O(1) average lookup. Since 3.7, dicts preserve insertion order — relied on by language spec, not an implementation detail.

dict.get — 安全取值

d = {"a": 1}
d["b"]              # KeyError
d.get("b")          # None
d.get("b", 0)       # 0   (默认值)
# 嵌套取值的常见写法:
d.get("user", {}).get("name", "anonymous")

d[k] raises KeyError; d.get(k, default) returns the default. Chain .get with empty dict default for safe nested access.

dict.setdefault — 一次性"取 or 初始化"

groups = {}
for name, group in pairs:
    groups.setdefault(group, []).append(name)
# 等价于:
from collections import defaultdict
groups = defaultdict(list)
for name, group in pairs:
    groups[group].append(name)

setdefault returns the existing value, or sets and returns the default. defaultdict(list) is the cleaner alternative for grouping.

dict.update — 合并字典

a = {"x": 1, "y": 2}
b = {"y": 20, "z": 30}
a.update(b)              # a 变成 {"x":1, "y":20, "z":30}
# 3.5+ 解包合并(返回新字典):
merged = {**a, **b}
# 3.9+ | 运算符:
merged = a | b
a |= b                   # 原地合并

update mutates a in place. {**a, **b} or (3.9+) a | b returns a NEW dict. Later keys win on conflicts.

dict 推导式

{x: x * x for x in range(5)}              # {0:0, 1:1, 2:4, 3:9, 4:16}
{k: v for k, v in items if v is not None}  # 过滤 None 值
{v: k for k, v in d.items()}              # 反转 kv
# 多个源:
{k: a[k] + b[k] for k in a.keys() & b.keys()}  # 共同键求和

Same syntax as list comprehension but with key:value pairs. Useful for filtering Nones, inverting dicts, building lookup tables on the fly.

collections.Counter

from collections import Counter
c = Counter("abracadabra")
# Counter({'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1})
c.most_common(3)              # [('a', 5), ('b', 2), ('r', 2)]
c1 + c2                        # 计数相加
c1 - c2                        # 计数相减(负数被截)
c1 & c2, c1 | c2               # 取最小 / 最大

Counter is a dict subclass for counting hashables. most_common(n) gives the top n. Supports + - & | operators for multiset math.

collections.defaultdict

from collections import defaultdict
counts = defaultdict(int)        # 默认 0
for w in words:
    counts[w] += 1               # 不用先判 in
buckets = defaultdict(list)
for x in items:
    buckets[x.group].append(x)
nested = defaultdict(lambda: defaultdict(int))   # 嵌套 dict

defaultdict creates the default value on first access. defaultdict(int) for counting, defaultdict(list) for grouping, lambda for nested defaults.

OrderedDict(3.7 后基本可弃用)

from collections import OrderedDict
od = OrderedDict()
od["a"] = 1
od["b"] = 2
od.move_to_end("a")       # 移到末尾
od.popitem(last=False)    # 弹首元素(普通 dict 没这俩方法)

Since 3.7 regular dict preserves order — most uses of OrderedDict can be replaced. Keep it only when you need move_to_end / popitem(last=False).

Set (5)

set 创建与基本操作

s = {1, 2, 3}
empty = set()           # 注意:{} 是 dict 不是 set
s.add(4)
s.discard(99)           # 不抛错;remove(99) 会抛 KeyError
2 in s                  # O(1)
len(s)

Sets are unordered, unique, O(1) membership. EMPTY set is set(), not {} (that's an empty dict). discard() is the safe remove.

set 交并差

a = {1, 2, 3}
b = {2, 3, 4}
a | b      # 并集 {1, 2, 3, 4}
a & b      # 交集 {2, 3}
a - b      # 差集 {1}
a ^ b      # 对称差 {1, 4}
a <= b     # 子集判断
a >= b     # 超集判断

Set operators are the readable way. Also available as .union() .intersection() .difference() .symmetric_difference() — but operators win on conciseness.

frozenset — 可哈希的不可变集合

fs = frozenset([1, 2, 3])
# 可以做 dict 的键、放进 set 里
d = {fs: "value"}
s = {frozenset([1, 2]), frozenset([3, 4])}

frozenset is immutable and hashable — can be a dict key or live inside another set. Regular sets cannot do either.

set 去重(保留顺序与否)

# 简单去重,不保留顺序:
list(set([1, 2, 2, 3, 1]))     # 顺序不稳定
# 保留顺序去重(3.7+ dict 保序):
list(dict.fromkeys([1, 2, 2, 3, 1]))   # [1, 2, 3]

set() loses order. dict.fromkeys() preserves first-seen order (since 3.7 dicts are insertion-ordered).

集合推导式

{x * x for x in range(10)}         # {0, 1, 4, 9, ..., 81}
{w.lower() for w in words}         # 去重 + 小写
# 一句话拿独立词数:
unique_words = len({w.lower() for w in text.split()})

Same syntax as list/dict comprehensions but with {} (no key:). One-liner for "count distinct" style problems.

Tuple / dataclass (4)

tuple 基础与不可变性

t = (1, 2, 3)
t = 1, 2, 3            # 括号可省,逗号才是关键
single = (1,)          # 单元素元组要加逗号!
empty = ()
# 不可变 —— 不能改:
# t[0] = 99  → TypeError
a, b, c = t            # 拆包

A tuple is defined by the COMMA, not the parens. Single-element tuple needs trailing comma: (1,) — (1) is just the int 1.

namedtuple — 轻量数据结构

from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
p.x, p.y           # 3, 4
p[0]               # 3   (也支持索引)
p._asdict()        # {"x": 3, "y": 4}
Point(**{"x": 5, "y": 6})

namedtuple gives tuples named fields — immutable, lightweight, picklable. For more features (defaults, methods), use dataclass instead.

dataclass — 现代数据类

from dataclasses import dataclass, field
@dataclass
class User:
    name: str
    age: int = 0
    tags: list[str] = field(default_factory=list)   # 可变默认值必须 factory

u = User("Lei", 30)
u.age = 31           # 默认可变
@dataclass(frozen=True)   # 不可变版本
class Point:
    x: float
    y: float

dataclass (3.7+) auto-generates __init__, __repr__, __eq__. Use field(default_factory=list) for mutable defaults. frozen=True for immutable.

tuple 解构与 *rest

a, b, c = (1, 2, 3)
first, *rest = [1, 2, 3, 4]       # 1, [2, 3, 4]
*init, last = [1, 2, 3, 4]        # [1, 2, 3], 4
a, *_, b = range(10)              # 头尾,中间扔掉
# 函数返回多值常用:
def divmod_(a, b):
    return a // b, a % b
q, r = divmod_(10, 3)

Tuple unpacking with *rest captures the middle / tail. Returning multiple values from a function is just returning a tuple — unpack at the call site.

Control flow (5)

if / elif / else

if x > 0:
    print("正")
elif x < 0:
    print("负")
else:
    print("零")
# 三元(条件表达式):
label = "正" if x > 0 else "非正"

Standard branching. Python uses elif (not else if). Ternary syntax: value_if_true if cond else value_if_false (cond in the MIDDLE — different from C/JS).

for / for-else

for x in items:
    if x < 0:
        break
else:
    print("没遇到负数")     # break 没触发才会跑

for i in range(5): print(i)
for i in range(2, 10, 2): print(i)    # 2, 4, 6, 8

for-else: the else runs when the loop completes without break — perfect for "search and notify if not found" patterns.

while / break / continue

while queue:
    x = queue.pop(0)
    if x is None:
        continue
    if x == "stop":
        break
    process(x)
# while-else 同样:else 在没 break 时跑

while runs as long as the condition is truthy. break exits the loop; continue skips to the next iteration. while-else also exists.

match / case(3.10+ 模式匹配)

def http_status(code: int) -> str:
    match code:
        case 200 | 201 | 204:
            return "OK"
        case 301 | 302:
            return "Redirect"
        case 400 | 404:
            return "Client error"
        case n if 500 <= n < 600:    # guard
            return "Server error"
        case _:
            return "Unknown"

# 解构匹配:
match point:
    case (0, 0): return "原点"
    case (x, 0): return f"X 轴 {x}"
    case (0, y): return f"Y 轴 {y}"
    case (x, y): return f"({x},{y})"

Structural pattern matching (3.10+). Use | for or, guards with `if`, and tuple/dict/class patterns for destructuring. Always end with case _: as the default.

walrus := 海象运算符(3.8+)

# 在 while 条件里赋值 + 判断:
while chunk := f.read(4096):
    process(chunk)

# if 里赋值 + 用:
if (n := len(items)) > 10:
    print(f"too many: {n}")

# 推导里复用计算结果:
[y for x in data if (y := expensive(x)) is not None]

The walrus := assigns AND returns. Best for loop conditions that need the value AND a check, or list comps that re-use a computed value.

Function (8)

def 定义函数 / 默认参数

def greet(name: str, greeting: str = "Hello") -> str:
    return f"{greeting}, {name}!"

greet("Lei")                        # "Hello, Lei!"
greet("Lei", greeting="嗨")          # 关键字参数

# 坑:可变默认值(永远不要这样写)
def add(item, items=[]):            # ❌ 所有调用共享同一个 list
    items.append(item)
    return items
def add(item, items=None):          # ✅ 正确写法
    if items is None:
        items = []
    items.append(item)
    return items

Default arguments are evaluated ONCE at def time — never use mutable defaults like [] or {}. Use None and create inside.

lambda 匿名函数

add = lambda a, b: a + b
sorted(rows, key=lambda r: r[1])
list(filter(lambda x: x > 0, nums))
# lambda 只能写单个表达式,不能有 return / for / 多行
# 多行逻辑就老老实实 def

lambda is single-expression only — no statements, no multi-line. Use it for short keys or callbacks; otherwise write a real def.

*args 与 **kwargs

def fn(*args, **kwargs):
    print(args)      # 元组
    print(kwargs)    # 字典
fn(1, 2, 3, name="Lei")
# 转发参数(装饰器常用):
def wrapper(*args, **kwargs):
    return inner(*args, **kwargs)
# 强制关键字参数(* 之后必须 keyword):
def connect(host, *, port=80, ssl=False):
    pass
connect("x", port=443)        # ✅
# connect("x", 443)            # ❌ TypeError

*args collects positional args as a tuple; **kwargs collects keyword args as a dict. Bare * forces everything after to be keyword-only — great API hygiene.

type hint 类型注解

def greet(name: str, times: int = 1) -> str:
    return ("Hi " + name + "! ") * times

from typing import Optional, Union, Callable
def get(key: str) -> Optional[str]: ...
# 3.10+ 简化:
def get(key: str) -> str | None: ...
# 3.9+ 内置泛型:
def parse(items: list[int]) -> dict[str, int]: ...
# 函数类型:
def apply(fn: Callable[[int, int], int], a: int, b: int) -> int:
    return fn(a, b)

Type hints are optional but checked by mypy / pyright. 3.9+ accepts list[int] and dict[str, int] directly; 3.10+ accepts X | Y instead of Union.

装饰器 decorator

from functools import wraps
import time
def timed(fn):
    @wraps(fn)                    # 保留 fn 的 __name__ / docstring
    def inner(*args, **kwargs):
        t = time.perf_counter()
        result = fn(*args, **kwargs)
        print(f"{fn.__name__} took {time.perf_counter()-t:.3f}s")
        return result
    return inner

@timed
def slow():
    time.sleep(1)

A decorator is a function that takes and returns a function. Always use @functools.wraps to preserve the original's __name__ and docstring.

闭包与 late binding 坑

# 经典 late binding 坑:
fns = [lambda: i for i in range(3)]
[f() for f in fns]            # [2, 2, 2],不是 [0, 1, 2]
# 修复:默认参数当时绑定
fns = [lambda i=i: i for i in range(3)]
[f() for f in fns]            # [0, 1, 2]

Lambdas in a loop capture the variable by REFERENCE, not by value — all see the final i. Fix with `i=i` default arg to snapshot at def time.

global 与 nonlocal

count = 0
def inc():
    global count        # 不写就报 UnboundLocalError
    count += 1

def make_counter():
    n = 0
    def inc():
        nonlocal n      # 修改外层函数的 n(不是 global)
        n += 1
        return n
    return inc

Inside a function, reading a name from outer scope works, but ASSIGNING to it requires global (module level) or nonlocal (enclosing function).

partial — 预绑定参数

from functools import partial
def power(base, exp):
    return base ** exp

square = partial(power, exp=2)
cube = partial(power, exp=3)
square(5)        # 25
cube(3)          # 27

# 实战:给 sorted 传带固定参数的 key
sorted(rows, key=partial(getattr, default=None))

partial creates a new callable with some args pre-filled. Cleaner than lambda when you just need argument binding.

Class (7)

class 基础 / __init__ / self

class User:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age
    def greet(self) -> str:
        return f"Hi, I'm {self.name}"

u = User("Lei", 30)
u.greet()

__init__ runs after instance creation. self is the instance — by convention, but you MUST pass it explicitly in every method definition.

@property — 属性访问的优雅封装

class Circle:
    def __init__(self, r):
        self.r = r
    @property
    def area(self):
        return 3.14159 * self.r ** 2
    @area.setter
    def area(self, value):
        self.r = (value / 3.14159) ** 0.5

c = Circle(5)
c.area          # 不用 c.area(),直接像属性一样访问
c.area = 100    # 触发 setter

@property turns a method into an attribute lookup. @prop.setter defines the write side. Use when validation or derivation is needed.

@classmethod / @staticmethod

class User:
    def __init__(self, name):
        self.name = name
    @classmethod
    def from_dict(cls, d):       # 工厂方法
        return cls(d["name"])
    @staticmethod
    def is_valid_name(s):        # 与类相关但不需要 cls / self
        return s.isalpha()

u = User.from_dict({"name": "Lei"})
User.is_valid_name("Lei")

classmethod takes cls (the class) — for factory methods. staticmethod takes nothing — for utility functions that live in the class namespace.

dunder methods — 让对象表现像内置类型

class Money:
    def __init__(self, amount, currency):
        self.amount = amount
        self.currency = currency
    def __repr__(self):
        return f"Money({self.amount}, '{self.currency}')"
    def __str__(self):
        return f"{self.amount:.2f} {self.currency}"
    def __eq__(self, other):
        return (self.amount, self.currency) == (other.amount, other.currency)
    def __hash__(self):
        return hash((self.amount, self.currency))
    def __lt__(self, other):
        return self.amount < other.amount
    def __add__(self, other):
        return Money(self.amount + other.amount, self.currency)

Define __repr__ for debug print, __str__ for user print, __eq__/__hash__ for dict keys & sets, __lt__ for sorting, __add__ for + operator.

继承与 super

class Animal:
    def __init__(self, name):
        self.name = name
    def speak(self):
        return "..."

class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)        # 调父类 __init__
        self.breed = breed
    def speak(self):                  # 覆盖
        return "Woof!"

Inherit with class Sub(Base). Call super().method() to delegate to the parent. Multiple inheritance follows MRO (method resolution order).

@dataclass + frozen=True + slots

from dataclasses import dataclass

@dataclass(frozen=True, slots=True)    # 3.10+ slots=True
class Point:
    x: float
    y: float

p = Point(3, 4)
# p.x = 99   → FrozenInstanceError   不可变
# p.z = 99   → AttributeError        slots 禁止新属性
hash(p)      # frozen=True 自动可哈希

frozen=True makes the instance immutable + hashable. slots=True (3.10+) uses __slots__ to save memory and prevent typos creating new attrs.

__enter__ / __exit__ 自定义上下文管理

class Timer:
    def __enter__(self):
        import time
        self.t = time.perf_counter()
        return self
    def __exit__(self, exc_type, exc, tb):
        import time
        print(f"耗时 {time.perf_counter() - self.t:.3f}s")
        return False     # False / None 表示不吞异常

with Timer():
    slow_op()

# 或用 @contextmanager 装饰生成器:
from contextlib import contextmanager
@contextmanager
def open_db():
    conn = connect()
    try:
        yield conn
    finally:
        conn.close()

Implement __enter__/__exit__ on a class — or simpler: write a generator and decorate with @contextmanager. Always cleanup in finally / __exit__.

File & I/O (5)

open 与 with — 读写文件

# 读文本(自动指定 encoding,别依赖系统默认!)
with open("a.txt", "r", encoding="utf-8") as f:
    content = f.read()

# 一行行读(大文件友好,不全部加载)
with open("big.log", encoding="utf-8") as f:
    for line in f:
        process(line.rstrip("\n"))

# 写文本
with open("out.txt", "w", encoding="utf-8") as f:
    f.write("hello\n")
    f.writelines(["a\n", "b\n"])

# 追加
with open("out.txt", "a", encoding="utf-8") as f:
    f.write("more\n")

# 二进制
with open("img.png", "rb") as f:
    data = f.read()

Always use `with` — it closes the file even on exception. ALWAYS pass encoding="utf-8" explicitly; the OS default differs across platforms.

pathlib — 现代路径操作

from pathlib import Path
p = Path("data") / "users" / "lei.json"   # / 操作符拼路径
p.exists()
p.is_file(), p.is_dir()
p.parent, p.name, p.stem, p.suffix
p.read_text(encoding="utf-8")
p.write_text("hello", encoding="utf-8")
list(Path(".").glob("*.py"))              # 通配
list(Path(".").rglob("*.py"))             # 递归
Path("out").mkdir(parents=True, exist_ok=True)

pathlib (3.4+) replaces os.path string-mangling with real Path objects. Use the / operator to join — never string concat or os.path.join.

json — 读写 JSON

import json

# 字符串 ↔ 对象
data = json.loads('{"a": 1}')
s = json.dumps({"a": 1})                   # 紧凑
s = json.dumps(obj, indent=2, ensure_ascii=False)   # 缩进 + 中文不转义

# 文件 ↔ 对象
with open("data.json", encoding="utf-8") as f:
    data = json.load(f)
with open("out.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)

load/dump = file; loads/dumps = string. ALWAYS pass ensure_ascii=False if you have non-ASCII data, otherwise 中文 becomes \u escapes.

csv — 读写 CSV

import csv

# 读
with open("data.csv", encoding="utf-8", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], row["age"])

# 写
with open("out.csv", "w", encoding="utf-8", newline="") as f:
    writer = csv.DictWriter(f, fieldnames=["name", "age"])
    writer.writeheader()
    writer.writerow({"name": "Lei", "age": 30})

ALWAYS open CSV files with newline="" — otherwise Windows writes blank lines between rows. DictReader/DictWriter handle headers automatically.

tempfile — 临时文件 / 目录

import tempfile
# 临时文件(自动删除):
with tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False) as f:
    f.write("data")
    path = f.name

# 临时目录:
with tempfile.TemporaryDirectory() as d:
    p = Path(d) / "x.txt"
    p.write_text("hi")
    # 出 with 时 d 整个被删

tempfile creates OS-managed temp paths that survive across reboots. NamedTemporaryFile + TemporaryDirectory auto-cleanup on context exit.

Exception (4)

try / except / else / finally

try:
    n = int(s)
    data = fetch(n)
except ValueError as e:
    print(f"输入不是数字: {e}")
except (KeyError, IndexError) as e:    # 多种异常一起
    print(f"数据问题: {e}")
except Exception as e:                  # 兜底
    print(f"其他错误: {e}")
    raise                                # 抛出去
else:
    print("没出错才跑这里")
finally:
    cleanup()                            # 出不出错都跑

else runs only when NO exception fired. finally always runs (cleanup). Bare `except:` catches even KeyboardInterrupt — almost always wrong; use `except Exception:`.

raise — 抛异常 / 链式异常

raise ValueError("age 不能为负")
raise ValueError(f"非法值 {x}")

# 包装别人的异常(保留原始 traceback)
try:
    int(s)
except ValueError as e:
    raise ParseError("解析失败") from e

# 想隐藏原始链:
raise ParseError("...") from None

raise X from Y wraps Y while preserving the cause chain — the traceback shows both. raise X from None hides the original (rarely what you want).

自定义异常

class APIError(Exception):
    """所有 API 错误的基类"""

class RateLimitError(APIError):
    def __init__(self, retry_after: int):
        super().__init__(f"rate limited, retry after {retry_after}s")
        self.retry_after = retry_after

try:
    call_api()
except RateLimitError as e:
    time.sleep(e.retry_after)
except APIError:
    log.exception("api failed")

Define a base exception per package and subclass it. Lets callers catch the broad family OR the specific type. Always inherit from Exception, not BaseException.

contextlib.suppress — 优雅忽略异常

from contextlib import suppress

# 老写法:
try:
    os.remove("not-exist.txt")
except FileNotFoundError:
    pass

# 新写法:
with suppress(FileNotFoundError):
    os.remove("not-exist.txt")

# 多个异常:
with suppress(KeyError, IndexError):
    value = data["k"][0]

suppress(ExceptionType) is a context manager that swallows those exceptions silently — cleaner than try/except/pass for one-line ops.

Iter / generator (6)

iter / next — 迭代器协议

it = iter([1, 2, 3])
next(it)      # 1
next(it)      # 2
next(it)      # 3
next(it)      # StopIteration
next(it, "默认")    # 第二个参数避免 StopIteration

# 任何实现 __iter__ + __next__ 的对象都是迭代器
class CountUp:
    def __init__(self, n): self.n = n; self.i = 0
    def __iter__(self): return self
    def __next__(self):
        if self.i >= self.n: raise StopIteration
        self.i += 1
        return self.i

iter(obj) returns an iterator. next(it) advances it. next(it, default) is the safe way to avoid StopIteration. Most for loops just call these for you.

generator / yield — 惰性生成

def count_up(n):
    i = 0
    while i < n:
        yield i        # 每次 yield 暂停,下次 next() 继续
        i += 1

for x in count_up(5): print(x)
# 生成器表达式(节省内存):
squares = (x * x for x in range(1_000_000))
sum(squares)

yield turns a function into a generator — produces values lazily, one at a time, holding state between calls. Generator expressions use () instead of [].

yield from — 委托给子生成器

def flatten(nested):
    for item in nested:
        if isinstance(item, list):
            yield from flatten(item)    # 递归
        else:
            yield item

list(flatten([1, [2, [3, [4]]], 5]))    # [1, 2, 3, 4, 5]

yield from delegates iteration to another iterable, including all sub-yields. Cleaner than a manual for-loop with yield.

itertools 常用:chain / groupby / permutations

from itertools import chain, groupby, permutations, combinations, product, accumulate, islice
list(chain([1, 2], [3, 4]))                    # [1, 2, 3, 4]
list(chain.from_iterable([[1, 2], [3, 4]]))    # [1, 2, 3, 4]
list(permutations([1, 2, 3], 2))               # 排列 (1,2),(1,3),(2,1)...
list(combinations([1, 2, 3], 2))               # 组合 (1,2),(1,3),(2,3)
list(product([0, 1], repeat=3))                # 笛卡尔积
list(accumulate([1, 2, 3, 4]))                 # [1, 3, 6, 10] 前缀和
list(islice(big_iter, 10))                     # 取前 10 个

# groupby 必须先排序!
rows = sorted(rows, key=itemgetter("group"))
for g, items in groupby(rows, key=itemgetter("group")):
    print(g, list(items))

itertools is the standard library iterator zoo. The #1 gotcha: groupby only groups CONSECUTIVE equal elements — you must sort first.

functools.reduce / lru_cache

from functools import reduce, lru_cache, cache
reduce(lambda a, b: a + b, [1, 2, 3, 4])     # 10
reduce(lambda a, b: a + b, [1, 2, 3, 4], 100)  # 110 (初值)

@lru_cache(maxsize=None)                      # 自动记忆
def fib(n):
    return n if n < 2 else fib(n-1) + fib(n-2)

@cache     # 3.9+ 简化版 lru_cache(maxsize=None)
def f(x): ...

reduce folds a binary op across an iterable. @lru_cache memoizes — turns exponential recursion into linear. @cache (3.9+) is the shorthand.

zip_longest / takewhile / dropwhile

from itertools import zip_longest, takewhile, dropwhile
list(zip_longest([1, 2], ["a", "b", "c"], fillvalue="-"))
# [(1, 'a'), (2, 'b'), ('-', 'c')]   长度对不齐用 fillvalue 填
list(takewhile(lambda x: x < 5, [1, 3, 4, 6, 2]))   # [1, 3, 4]   遇到 False 就停
list(dropwhile(lambda x: x < 5, [1, 3, 4, 6, 2]))   # [6, 2]      跳到第一个 False

zip_longest pads the shorter iterable. takewhile / dropwhile slice an iterable at the first False predicate — useful for streaming data.

Async (5)

async / await 基础

import asyncio

async def fetch(url):
    await asyncio.sleep(1)         # 模拟 IO
    return f"data from {url}"

async def main():
    data = await fetch("https://x.com")
    print(data)

asyncio.run(main())                # 入口必须这一行

async def declares a coroutine. await yields control. asyncio.run() is the canonical entrypoint — never call run() inside an already-running loop.

asyncio.gather — 并发执行

async def main():
    urls = ["a", "b", "c"]
    # 串行(慢):
    results = [await fetch(u) for u in urls]
    # 并发(快 N 倍):
    results = await asyncio.gather(*[fetch(u) for u in urls])
    # 一个失败别全部炸:
    results = await asyncio.gather(*tasks, return_exceptions=True)
    # 3.11+ TaskGroup(推荐写法,更安全):
    async with asyncio.TaskGroup() as tg:
        ts = [tg.create_task(fetch(u)) for u in urls]
    results = [t.result() for t in ts]

gather runs coroutines concurrently. return_exceptions=True prevents one failure from cancelling the rest. 3.11+ TaskGroup is the modern, safer pattern.

asyncio.create_task / wait / timeout

# 立刻调度,不等:
task = asyncio.create_task(fetch("x"))
# 之后再 await:
result = await task

# 限时:3.11+
async with asyncio.timeout(5):
    await long_op()
# 旧写法 3.10-:
try:
    await asyncio.wait_for(long_op(), timeout=5)
except asyncio.TimeoutError:
    ...

# 等任一个完成:
done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)

create_task schedules immediately. asyncio.timeout (3.11+) is the new context-manager way to limit time; older code uses wait_for.

async for / async with

# 异步迭代器
async def fetch_pages():
    async for chunk in client.stream("..."):
        yield chunk

# 异步上下文管理
async with aiohttp.ClientSession() as session:
    async with session.get(url) as resp:
        text = await resp.text()

Use async for / async with on objects that define __aiter__ / __aenter__ — common in HTTP clients, DB drivers, file streams.

asyncio.Queue / Semaphore — 并发原语

# Semaphore 限并发:
sem = asyncio.Semaphore(10)
async def fetch_limited(url):
    async with sem:
        return await fetch(url)

# Queue 生产消费:
q = asyncio.Queue(maxsize=100)
async def producer():
    for x in items:
        await q.put(x)
    await q.put(None)        # 哨兵
async def consumer():
    while (x := await q.get()) is not None:
        process(x)
        q.task_done()

Semaphore caps concurrent operations (e.g., HTTP calls). Queue is the producer/consumer primitive — use None / sentinel to signal completion.

Typing (7)

typing 基础:List / Dict / Tuple / Set

# 3.8 写法(typing 模块):
from typing import List, Dict, Tuple, Set
def fn(xs: List[int], d: Dict[str, int]) -> Tuple[int, ...]: ...

# 3.9+ 推荐用内置(不用 import):
def fn(xs: list[int], d: dict[str, int]) -> tuple[int, ...]: ...

# tuple 长度固定写法:
Tuple[int, str, float]   # 三元素,类型不同
tuple[int, ...]          # 任意长度,元素都是 int

3.9+ supports list[int] / dict[str, int] / set[X] directly. The typing module aliases (List, Dict) are still valid but no longer required.

Optional / Union / None

from typing import Optional, Union
def get(k: str) -> Optional[str]: ...    # str 或 None
def x(v: Union[int, str]): ...           # int 或 str

# 3.10+ 推荐用 | :
def get(k: str) -> str | None: ...
def x(v: int | str): ...

# Optional[T] === T | None
# 它不是"可省略",而是"可能为 None",别误解

Optional[T] means T or None — not "optional argument". 3.10+ uses T | None / int | str instead of Optional / Union. Cleaner.

TypedDict — 结构化字典

from typing import TypedDict, NotRequired

class User(TypedDict):
    name: str
    age: int
    email: NotRequired[str]     # 3.11+

def greet(u: User) -> str:
    return f"Hi, {u['name']}"

greet({"name": "Lei", "age": 30})           # ✅
# greet({"name": "Lei"})                     # mypy 报错:缺 age

TypedDict types dict shapes — useful for JSON-like data without writing a full class. 3.11+ adds NotRequired / Required for partial keys.

Protocol — 鸭子类型 + 静态检查

from typing import Protocol

class HasName(Protocol):
    name: str
    def greet(self) -> str: ...

def shout(x: HasName) -> str:
    return x.greet().upper()

# 任何有 name 属性 + greet() 方法的对象都满足 HasName
# 不用继承,结构匹配即可(structural typing)

Protocol (3.8+) is duck typing with static checking — any object with the right shape satisfies it, no inheritance needed. Python's answer to Go interfaces.

Generic / TypeVar — 泛型

from typing import TypeVar, Generic
T = TypeVar("T")

def first(xs: list[T]) -> T:
    return xs[0]

class Stack(Generic[T]):
    def __init__(self): self._items: list[T] = []
    def push(self, x: T): self._items.append(x)
    def pop(self) -> T: return self._items.pop()

# 3.12+ 新语法(不用 TypeVar):
def first[T](xs: list[T]) -> T:
    return xs[0]

TypeVar declares a generic parameter. Generic[T] makes a class generic. Python 3.12+ has cleaner inline syntax: def f[T](...).

Literal / Final / Annotated

from typing import Literal, Final, Annotated
def open_file(mode: Literal["r", "w", "rb", "wb"]): ...
open_file("r")     # ✅
# open_file("x")   # mypy 报错

MAX: Final = 100             # 不可重新赋值
PI: Final[float] = 3.14159

# Annotated 给类型加元数据(pydantic / fastapi 常用):
Age = Annotated[int, "0-150"]

Literal restricts to exact values — perfect for mode flags. Final marks constants. Annotated attaches metadata used by Pydantic, FastAPI, etc.

cast / overload — 类型断言与重载

from typing import cast, overload

# 告诉类型检查器"我知道这里是什么"
x = cast(int, obj["count"])      # 运行时啥都不做,只骗 mypy

# 函数重载(多个签名,一份实现):
@overload
def fetch(x: int) -> User: ...
@overload
def fetch(x: str) -> list[User]: ...
def fetch(x):
    # 真实实现
    return _do(x)

cast() is a typing-only assertion (zero runtime cost). @overload declares multiple signatures for the same function — useful when return type depends on input type.

Common pitfalls (9)

可变默认参数(mutable default argument)

# ❌ 错误(所有调用共享同一个 list):
def add(item, items=[]):
    items.append(item)
    return items
add(1)            # [1]
add(2)            # [1, 2]   不是 [2]!

# ✅ 正确:
def add(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

Default args are evaluated ONCE at def time. A default [] / {} / set() is shared across ALL calls — accumulates between calls. Always use None sentinel + initialize inside.

late binding 闭包(循环里的 lambda)

# ❌ 全是 2:
fns = [lambda: i for i in range(3)]
[f() for f in fns]      # [2, 2, 2]

# ✅ 默认参数当时固定:
fns = [lambda i=i: i for i in range(3)]
[f() for f in fns]      # [0, 1, 2]

Closures capture VARIABLES not VALUES — all lambdas see the final i. Fix by binding via default arg `i=i` so the current value is snapshotted at def time.

浅拷贝 vs 深拷贝

import copy
a = [[1, 2], [3, 4]]
b = a              # 同一个对象(引用)
b = a[:]           # 浅拷贝:外层新,内层共享
b = a.copy()       # 浅拷贝
b = copy.copy(a)   # 浅拷贝
b = copy.deepcopy(a)   # 深拷贝(递归)

a[0].append(99)
print(b)           # 浅拷贝下 b 也变了!

list slice / .copy() / copy.copy() are SHALLOW — inner objects are shared. copy.deepcopy() recursively clones everything. Choose based on whether inner data is mutated.

is vs ==(身份 vs 值相等)

a = [1, 2, 3]
b = [1, 2, 3]
a == b      # True   值相等
a is b      # False  不是同一个对象

# is 只对单例可靠:None / True / False / 小整数缓存等
x is None   # ✅ 推荐
x == None   # 能跑,不地道

# 坑:小整数缓存(-5 到 256)
a = 256; b = 256
a is b      # True  (缓存)
a = 257; b = 257
a is b      # 一般是 False

is checks identity (same object), == checks value. Use `is None` / `is True` / `is False` only — those are singletons. Never rely on small-int caching.

遍历时修改容器

# ❌ 边遍历边删 —— RuntimeError 或漏删
for x in list_:
    if x.bad:
        list_.remove(x)

# ✅ 倒序删 / 或新建一个:
for i in range(len(list_) - 1, -1, -1):
    if list_[i].bad:
        del list_[i]

xs = [x for x in xs if not x.bad]    # 最地道

# dict 也同样:
for k in list(d.keys()):     # list() 拷一份再删
    if d[k] is None:
        del d[k]

Mutating a list/dict while iterating it skips items or raises RuntimeError. Either iterate a copy (`list(d.keys())`) or build a new container via comprehension.

global / nonlocal 不写就 UnboundLocalError

count = 0
def inc():
    count += 1            # ❌ UnboundLocalError
                          # 因为函数里赋值了 count,Python 把它当本地变量

def inc():
    global count          # ✅ 显式声明
    count += 1

If you ASSIGN to a name anywhere in a function, Python treats it as local for the WHOLE function — even before the assignment line. Use global/nonlocal to declare otherwise.

整数除法 / vs //

7 / 2      # 3.5      (Python 3 一律返回 float)
7 // 2     # 3        整除
-7 // 2    # -4       向下取整(不是向 0 取整!)
divmod(7, 2)   # (3, 1)   商和余数一起

# 来自 Python 2 的代码可能假设 / 是整除 —— 升 3 时小心

In Python 3, / always returns float. // is floor division (rounds toward NEGATIVE infinity — -7 // 2 == -4, not -3). divmod() returns (quotient, remainder).

字符串拼接的性能陷阱

# ❌ O(n²) — 字符串不可变,每次 + 都拷贝整段
s = ""
for x in items:
    s += str(x)

# ✅ O(n) — 收集再 join
parts = []
for x in items:
    parts.append(str(x))
s = "".join(parts)

# 或者列表推导 + join:
s = "".join(str(x) for x in items)

Strings are immutable — `s += x` in a loop is O(n²) because every iteration copies the whole string. Collect into a list and join at the end for O(n).

except Exception 不要写裸 except

# ❌ 吞掉 KeyboardInterrupt 和 SystemExit
try:
    risky()
except:
    pass

# ✅ 抓 Exception 就够了
try:
    risky()
except Exception as e:
    log.exception(e)

Bare `except:` catches BaseException — including KeyboardInterrupt and SystemExit. You can't Ctrl+C out. Use `except Exception:` to catch all normal errors.

What this tool does

Searchable Python cheat sheet, 100+ idiomatic snippets developers actually type — not hello-world filler. Fifteen categories: basics (assign, numeric + Decimal, bool, None, isinstance, range), string (f-string + format spec, split / join, strip, replace + re.sub, slicing, UTF-8), list (append vs extend trap, comprehension with filter + ternary, sorted + key, enumerate, zip strict, dedupe preserving order), dict (.get, setdefault vs defaultdict, 3.9 | merge, Counter), set (| & - ^ operators, frozenset, dedupe), tuple (single-element comma, namedtuple, dataclass with field(default_factory), *rest), control (if / for-else / while, walrus :=, 3.10 match / case with guards), function (mutable-default trap, lambda, *args / **kwargs / keyword-only, type hints, decorator + functools.wraps, partial), class (__init__, @property, classmethod / staticmethod, dunder, super + MRO, dataclass frozen + slots, __enter__ / __exit__), file (encoding="utf-8" always, pathlib, json ensure_ascii=False, csv newline="", tempfile), exception (try / except / else / finally, raise from, custom hierarchy, contextlib.suppress), iter (next + default, yield, yield from, itertools chain / groupby / permutations / accumulate, functools.reduce + @lru_cache, zip_longest / takewhile), async (asyncio.run, gather + return_exceptions, create_task / timeout, async for / with, Queue + Semaphore, 3.11 TaskGroup), typing (3.9 list[int], 3.10 X | None, TypedDict + NotRequired, Protocol, TypeVar / Generic, Literal / Final, cast / overload), and pitfalls (mutable default, late-binding closure, shallow vs deep copy, is vs ==, mutate while iterate, UnboundLocalError, bare except, -7 // 2 == -4, O(n²) string concat). Every entry: bilingual title, runnable code, bilingual description, 1-2 variants. Search title / code / description / variants together. 100% client- side. Pair with SQL / curl / git / regex cheat sheets and JSON Formatter.

Tool details

Input
Files
The page exposes text boxes, numeric controls, file pickers, or structured inputs depending on the tool.
Output
Live result + Copy
The result area focuses on usable output, with copy, download, or preview actions when supported.
Privacy
May use a live lookup
A network call is detected in the component, so redact sensitive data when appropriate.
Save / share
No account required
Open the page and use it; whether results survive refresh depends on the tool.
Performance budget
Initial JS <= 30 KB
No WASM budget is declared, keeping the tool quick to open on mobile.
Best fit
Developer & DevOps · Developer
Category and role tags drive related tools, internal links, and quick fit checks.

How to use

  1. 1. Input

    Paste or drop your content into the tool panel.

  2. 2. Process

    Click the button. All processing is local in your browser.

  3. 3. Copy / Download

    Copy the result or download to disk in one click.

How Python Cheatsheet fits into your work

Use it in the small gaps between coding, reviewing, debugging, and shipping.

Developer jobs

  • Formatting, validating, shrinking, or inspecting code-adjacent text.
  • Preparing snippets for documentation, tickets, commits, or handoff.
  • Checking a small payload quickly without switching tools.

Developer checks

  • Run irreversible transforms like minify or obfuscate on a copy.
  • Keep secrets out of pasted snippets unless the tool explicitly stays local.
  • Use your normal tests or linter before shipping transformed code.

Good next steps

These links move the current task into a more complete workflow.

  1. 1 JSON Formatter & Validator Format, validate, and minify JSON instantly — right in your browser. Open
  2. 2 SQL Cheatsheet SQL cheat sheet — 100+ statements covering SELECT, JOIN, window functions, indexing, MySQL/PostgreSQL/SQLite differences. Open
  3. 3 curl Cheatsheet curl cheat sheet — 80+ curl commands for GET/POST/auth/upload/download/SSL/proxy, with real examples and pitfalls. Open

FAQ

Tool combos

Folks in your role tend to reach for these alongside this tool.

Made by Toolora · 100% client-side · Updated 2026-05-29