Skip to content

Python 速查表

适用于 Web、数据、AI 和自动化的多功能、易读语言。

01

入门

Hello World 与注释

Python 使用 # 作为注释,使用三引号作为文档字符串。print() 函数支持 sep 和 end 参数来自定义输出格式。文档字符串作为文档可通过 help() 和 __doc__ 访问。

python
# This is a single-line comment
"""
This is a
multi-line comment (docstring)
"""
print("Hello, World!")        # print to stdout
print("A", "B", "C", sep="-") # A-B-C
print("No newline", end="")   # suppress newline

缩进与代码块

与大多数语言不同,Python 使用缩进而非花括号来定义代码块。一致性至关重要——混合使用制表符和空格会导致 SyntaxError。PEP 8 建议每级使用 4 个空格。

python
# Python uses indentation (4 spaces) to define blocks
if True:
    print("inside if")
    if True:
        print("nested block")
print("outside block")

# No braces! Indentation IS the syntax
def func():
    x = 1
    return x + 1

输入与输出

input() 从标准输入读取字符串——需要数字时务必进行转换。使用 int()、float() 等进行转换。F-strings(Python 3.6+)是格式化字符串的首选方式。

python
# input() always returns a string
name = input("Enter your name: ")
age = int(input("Enter your age: "))  # convert to int

print(f"Hello {name}, you are {age} years old")

# formatted output
print("Pi is approximately {:.2f}".format(3.14159))
print(f"{1000000:,}")  # 1,000,000 with thousands separator

多语句与行续接

使用分号分隔一行中的多个语句(在惯用 Python 中很少见)。长行可以用反斜杠续接,或在 ()、[]、{} 中自动续接。为提高可读性,优先使用隐式续接。

python
# multiple statements on one line (discouraged)
a = 1; b = 2; c = 3

# explicit line continuation
total = 1 + 2 + 3 + \
        4 + 5 + 6

# implicit continuation inside brackets
nums = [
    1, 2, 3,
    4, 5, 6
]

result = (1 + 2
          + 3 + 4)

Python 执行

Python 脚本使用 'python script.py' 运行。REPL 允许交互式实验。在 python 指向 Python 2 的系统上始终使用 python3。shebang 行使脚本在 Unix 上可执行。

python
# Run a script
# $ python script.py

# Run interactively (REPL)
# $ python
# >>> 2 + 2
# 4

# Shebang line for Unix scripts
#!/usr/bin/env python3

# Check Python version
import sys
print(sys.version)
print(sys.version_info.major)  # 3
02

变量与数据类型

变量与动态类型

Python 使用动态类型——变量可以在运行时改变类型。使用 type() 检查,isinstance() 验证。Python 3.6+ 支持类型提示(name: str = 'Alice')以获得 IDE 支持,但运行时不强制执行。

python
# Python is dynamically typed - no declaration needed
name = "Alice"          # str
age = 30                # int
height = 5.7            # float
is_active = True        # bool
items = [1, 2, 3]       # list

# Type checking
print(type(name))       # <class 'str'>
print(isinstance(age, int))  # True

# Multiple assignment
x, y, z = 1, 2, 3
a = b = 0  # chain assignment

类型提示(Python 3.6+)

类型提示提高了代码可读性,并使 IDE 自动补全和使用 mypy 进行静态分析成为可能。它们在运行时不强制执行——Python 仍然是动态类型的。使用 Optional[X] 表示可能为 None 的值。

python
# Variable annotations
name: str = "Alice"
age: int = 30
scores: list[float] = [90.5, 85.0]

# Function annotations
def greet(name: str, times: int = 1) -> str:
    return (f"Hi {name}! " * times).strip()

# Optional and Union
from typing import Optional, Union
def find(id: int) -> Optional[str]:
    return "Alice" if id == 1 else None

# mypy for static type checking
# $ mypy script.py

类型转换

Python 有内置转换函数:int()、float()、str()、bool()、list()、tuple()、set()、dict()。假值包括 0、''、[]、{}、None、False。int() 向零截断,而 round() 使用银行家舍入法。

python
# String to number
num_str = str(42)          # "42"
num = int("42")            # 42
float_num = float("3.14")  # 3.14

# Number conversions
print(int(3.99))           # 3 (truncates toward zero)
print(int(-3.99))          # -3
print(round(3.14159, 2))   # 3.14

# Boolean conversion
print(bool(0))             # False
print(bool(""))            # False
print(bool([]))            # False
print(bool("anything"))    # True

# Collection conversions
print(list("abc"))         # ['a', 'b', 'c']
print(tuple([1, 2, 3]))    # (1, 2, 3)
print(set([1, 1, 2]))      # {1, 2}

数值类型

Python 整数具有任意精度(无溢出)。浮点数是 IEEE 754 双精度,存在常见的精度问题。复数是内置的。布尔值是 int 的子类(True==1,False==0)。在数字字面量中使用下划线以提高可读性。

python
# Integers (arbitrary precision)
big = 10 ** 100  # no overflow
print(type(big))  # <class 'int'>

# Floats (IEEE 754 double)
pi = 3.14159
print(0.1 + 0.2)  # 0.30000000000000004

# Complex numbers
z = 3 + 4j
print(z.real, z.imag)  # 3.0 4.0
print(abs(z))          # 5.0

# Boolean is subclass of int
print(isinstance(True, int))  # True
print(True + True)            # 2

# Underscores in numbers (3.6+)
million = 1_000_000
binary = 0b_1010_1010

常量与命名约定

Python 没有 const 关键字——ALL_CAPS 名称仅按约定作为常量(没有任何机制阻止重新赋值)。PEP 8 定义了命名规则:变量/函数使用 snake_case,类使用 PascalCase,常量使用 ALL_CAPS。前导下划线按约定表示“私有”;双下划线触发名称改写。

python
# Python has no true constants - convention only
MAX_SIZE = 100          # ALL_CAPS for constants
PI = 3.14159

# Naming conventions (PEP 8)
variable_name = "snake_case"      # variables, functions
ClassName = "PascalCase"          # classes
CONSTANT_VALUE = 100              # constants
_private_var = "underscore prefix" # private (convention)
__name_mangled = "double underscore" # name mangling

# dunder names (reserved)
__name__, __main__, __init__
03

字符串

字符串方法

字符串是不可变的——方法返回新字符串。find() 在未找到时返回 -1,而 index() 抛出 ValueError。使用 isalpha()/isdigit()/isalnum() 进行验证。str 类有 40 多个方法——用 dir(str) 探索。

python
s = "Hello, World"

# Case operations
print(s.upper())          # HELLO, WORLD
print(s.lower())          # hello, world
print(s.title())          # Hello, World
print(s.capitalize())     # Hello, world
print(s.swapcase())       # hELLO, wORLD

# Search & replace
print(s.find("World"))    # 7 (index, -1 if not found)
print(s.index("World"))   # 7 (raises ValueError if not found)
print(s.replace("o", "0"))  # Hell0, W0rld
print(s.count("l"))       # 3

# Validation
print("abc".isalpha())    # True
print("123".isdigit())    # True
print("  ".isspace())     # True

字符串格式化

F-strings 是格式化字符串的现代、最快且最易读的方式。它们支持冒号后的格式规范::.2f 表示 2 位小数,:>10 表示右对齐宽度 10,:, 表示千位分隔符。在新代码中避免使用 %-格式化。

python
name = "Alice"
age = 30

# f-strings (Python 3.6+) - PREFERRED
print(f"Hello, {name}! You are {age}.")
print(f"{name.upper()} is {age * 365} days old")
print(f"{3.14159:.2f}")      # 3.14
print(f"{42:>10}")           # right-align
print(f"{42:<10}")           # left-align
print(f"{42:^10}")           # center
print(f"{1000000:,}")        # 1,000,000

# str.format() method
print("Hello, {}!".format(name))
print("{name} is {age}".format(name="Bob", age=25))

# Old style (avoid in new code)
print("Hello, %s!" % name)

切片与索引

Python 切片语法 [start:stop:step] 功能强大——stop 是排他的。负索引从末尾计数。s[::-1] 是反转字符串的惯用方式。切片是安全的:超出范围的索引返回空字符串而不是抛出错误。

python
s = "Hello, World"

# Indexing (0-based, negative from end)
print(s[0])        # H
print(s[-1])       # d
print(s[7])        # W

# Slicing [start:stop:step]
print(s[0:5])      # Hello
print(s[7:])       # World
print(s[:5])       # Hello
print(s[::2])      # HloWrd (every 2nd char)
print(s[::-1])     # dlroW ,olleH (reverse!)

# Length
print(len(s))      # 12

# Slicing never raises IndexError
print(s[100:200])  # '' (empty string)

分割与连接

split() 将字符串分割为列表,join() 将列表合并为字符串。对于大量字符串的高效拼接,始终使用 join()——+ 运算符会创建中间字符串。partition() 精确分割为 3 部分(之前、分隔符、之后)。

python
# Split
csv = "a,b,c,d"
print(csv.split(","))          # ['a', 'b', 'c', 'd']
print(csv.split(",", 2))       # ['a', 'b', 'c,d'] (max 2 splits)

# Splitlines
text = "line1\nline2\nline3"
print(text.splitlines())       # ['line1', 'line2', 'line3']

# Partition (splits on first occurrence)
print("[email protected]".partition("@"))
# ('user', '@', 'domain.com')

# Join
words = ["Hello", "World"]
print(" ".join(words))         # Hello World
print("-".join(["2024", "01", "15"]))  # 2024-01-15
print("".join(["a", "b", "c"])) # abc

# String concatenation
s = "Hello" + " " + "World"
parts = ["a"]
parts += "b"  # NOT string concat - adds chars to list!

去除与填充

strip() 默认去除首尾空白字符,或指定的字符。zfill() 用前导零填充(对 ID 有用)。rjust/ljust/center 用可选的填充字符填充到指定宽度。

python
# Strip whitespace (or specified chars)
s = "  hello  "
print(s.strip())    # "hello"
print(s.lstrip())   # "hello  "
print(s.rstrip())   # "  hello"

# Strip specific characters
print("xxxhelloxxx".strip("x"))  # hello

# Padding / centering
print("42".zfill(5))      # 00042
print("hi".rjust(10))     # "        hi"
print("hi".ljust(10, "-")) # "hi--------"
print("hi".center(10, "*")) # "****hi****"

# expandtabs
print("a\tb".expandtabs(4))  # "a   b"

原始字符串与转义

原始字符串(r'...')将反斜杠视为字面量——对于正则表达式模式和 Windows 文件路径至关重要。三引号字符串保留换行符。字符串支持 * 运算符重复和 + 连接。

python
# Escape sequences
print("Line1\nLine2")     # newline
print("Tab\there")        # tab
print("Quote: \"hi\"")   # escaped quotes
print("Backslash: \\")   # literal backslash

# Raw strings (ignore escapes) - great for regex
path = r"C:\Users\name\file.txt"
regex = r"\d{3}-\d{4}"
print(path)  # C:\Users\name\file.txt

# Triple-quoted strings
multi = """
Multiple
lines
"""

# String multiplication
print("ab" * 3)  # ababab
04

数字与数学

算术运算符

Python 有 7 个算术运算符。/ 始终返回浮点数,// 是向下取整除法(向负无穷大方向舍入)。** 是幂运算(不是 ^——那是 XOR)。% 运算符的结果取除数的符号,与 C/Java 不同。

python
# Basic operators
print(7 + 3)   # 10  addition
print(7 - 3)   # 4   subtraction
print(7 * 3)   # 21  multiplication
print(7 / 3)   # 2.333...  true division (always float)
print(7 // 3)  # 2   floor division
print(7 % 3)   # 1   modulo (remainder)
print(7 ** 3)  # 343 exponentiation

# Floor division with negatives
print(-7 // 3)  # -3 (rounds toward negative infinity)
print(-7 % 3)   # 2 (result has same sign as divisor)

# Augmented assignment
x = 10
x += 5   # x = x + 5
x **= 2  # x = x ** 2

Math 模块

math 模块提供数学函数和常量。所有三角函数使用弧度——用 math.radians()/degrees() 转换。math.gcd() 求最大公约数。对于复数,使用 cmath 模块。

python
import math

# Constants
print(math.pi)       # 3.141592653589793
print(math.e)        # 2.718281828459045
print(math.inf)      # inf
print(math.nan)      # nan

# Functions
print(math.sqrt(16))     # 4.0
print(math.pow(2, 10))   # 1024.0
print(math.log(100, 10)) # 2.0 (log base 10)
print(math.log(math.e))  # 1.0 (natural log)
print(math.factorial(5)) # 120
print(math.gcd(12, 8))   # 4

# Rounding
print(math.floor(3.7))   # 3
print(math.ceil(3.2))    # 4
print(math.trunc(-3.7))  # -3 (toward zero)

# Trigonometry (radians)
print(math.sin(math.pi / 2))  # 1.0
print(math.degrees(math.pi))  # 180.0

Random 模块

random 模块使用 Mersenne Twister 伪随机数生成器——不是加密安全的。安全用途请使用 secrets 模块。random.sample() 选取唯一项,random.choices() 允许重复。设置种子以在测试中获得可复现的结果。

python
import random

# Random integers
print(random.randint(1, 100))    # 1 to 100 inclusive
print(random.randrange(0, 10, 2)) # even number 0,2,4,6,8

# Random floats
print(random.random())           # 0.0 to 1.0
print(random.uniform(1.0, 10.0)) # random float in range

# Choice & sampling
colors = ["red", "green", "blue"]
print(random.choice(colors))           # one random item
print(random.sample(colors, 2))        # 2 unique items
print(random.choices(colors, k=5))     # 5 items (with replacement)

# Shuffle (in-place)
nums = [1, 2, 3, 4, 5]
random.shuffle(nums)
print(nums)

# Reproducible randomness
random.seed(42)  # same seed = same sequence

Decimal 与 Fractions

在浮点精度误差不可接受的财务计算中使用 Decimal(例如货币)。使用 Fraction 进行精确的有理数运算。两者都比浮点数慢,但避免了舍入误差。始终从字符串而非浮点数构造 Decimal。

python
from decimal import Decimal, getcontext
from fractions import Fraction

# Float precision issues
print(0.1 + 0.2)  # 0.30000000000000004

# Decimal for exact decimal arithmetic
a = Decimal("0.1")
b = Decimal("0.2")
print(a + b)  # 0.3 (exact!)

# Set precision
getcontext().prec = 6
print(Decimal(1) / Decimal(7))  # 0.142857

# Fractions for exact rational arithmetic
f1 = Fraction(1, 3)
f2 = Fraction(1, 6)
print(f1 + f2)  # 1/2
print(float(f1))  # 0.3333...

# Fraction from string
print(Fraction("3/4"))  # 3/4

位运算符

位运算符操作整数的各个位。Python 整数具有任意精度,因此移位的工作方式与定宽语言不同。常见用途:标志、掩码、低级协议解析。x & (x-1) == 0 检查 x 是否为 2 的幂。

python
# Bitwise operators work on integers
a = 0b1010  # 10
b = 0b1100  # 12

print(a & b)   # 8  (0b1000) AND
print(a | b)   # 14 (0b1110) OR
print(a ^ b)   # 6  (0b0110) XOR
print(~a)      # -11 (NOT, two's complement)
print(a << 2)  # 40 (left shift, multiply by 4)
print(a >> 1)  # 5  (right shift, divide by 2)

# Binary representation
print(bin(10))   # 0b1010
print(hex(255))  # 0xff
print(oct(8))    # 0o10
print(int("1010", 2))  # 10 (parse binary)

# Common tricks
print(5 & 1)     # 1 (check odd: nonzero = odd)
print(8 & (8-1)) # 0 (check power of 2)
05

数据结构

列表

列表是 Python 最通用的数据结构——有序、可变且可混合类型。append() 是 O(1),insert(0, x) 是 O(n)。使用 collections.deque 在两端进行快速操作。sort() 是原地排序,sorted() 返回新列表。

python
# Lists are ordered, mutable sequences
nums = [1, 2, 3, 4, 5]
mixed = [1, "hello", True, 3.14]

# Adding elements
nums.append(6)           # [1,2,3,4,5,6]
nums.insert(0, 0)        # [0,1,2,3,4,5,6]
nums.extend([7, 8])      # extend with another list

# Removing elements
nums.remove(0)           # remove by value
popped = nums.pop()      # remove & return last
popped = nums.pop(0)     # remove & return by index
del nums[0]              # delete by index
nums.clear()             # remove all

# Slicing (same as strings)
nums = [1, 2, 3, 4, 5]
print(nums[1:3])    # [2, 3]
print(nums[::-1])   # [5, 4, 3, 2, 1] reverse

# Sorting
nums.sort()              # in-place sort
nums.sort(reverse=True)  # descending
sorted_nums = sorted(nums)  # returns new list

元组

元组是不可变的,比列表更快。用于固定集合、多个返回值和字典键(列表不能作为键)。命名元组提供字段名以提高可读性。单元素元组需要尾随逗号。

python
# Tuples are ordered, IMMUTABLE sequences
point = (3, 4)
single = (42,)     # note the comma for single-element tuple
empty = ()

# Packing & unpacking
coordinates = 10, 20, 30  # packing
x, y, z = coordinates     # unpacking
x, y = y, x               # swap values!

# Multiple return values
def min_max(nums):
    return min(nums), max(nums)

lo, hi = min_max([3, 1, 4, 1, 5])

# Named tuples (readable)
from collections import namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y)       # 3 4
print(p[0], p[1])     # 3 4

# Tuples are immutable but can contain mutable objects
t = (1, [2, 3])
t[1].append(4)  # OK: (1, [2, 3, 4])

字典

字典是哈希表——查找/插入/删除平均为 O(1)。键必须是可哈希的(不可变)。从 Python 3.7 起,字典保持插入顺序。使用 get() 避免 KeyError。字典推导式优雅地创建字典。

python
# Dicts are key-value mappings (insertion-ordered since 3.7)
user = {"name": "Alice", "age": 30}

# Access
print(user["name"])          # Alice
print(user.get("email"))     # None (no KeyError)
print(user.get("email", "N/A"))  # N/A (default)

# Add/update
user["email"] = "[email protected]"    # add
user["age"] = 31             # update
user.setdefault("role", "user")  # set if missing

# Delete
del user["email"]
val = user.pop("age")        # remove & return
# user.clear()               # remove all

# Iteration
for key in user:             # keys
    print(key)
for k, v in user.items():    # key-value pairs
    print(k, v)
for v in user.values():      # values
    print(v)

# Dict comprehension
squares = {x: x**2 for x in range(5)}

# Merge dicts (3.9+)
merged = {"a": 1} | {"b": 2}

集合

集合是无序的唯一可哈希元素集合。它们擅长成员测试(O(1) vs 列表的 O(n))和集合代数(并集、交集、差集)。frozenset 是不可变且可哈希的。不保证顺序。

python
# Sets are unordered collections of unique elements
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}

# Set operations
print(a | b)    # union: {1, 2, 3, 4, 5, 6}
print(a & b)    # intersection: {3, 4}
print(a - b)    # difference: {1, 2}
print(a ^ b)    # symmetric difference: {1, 2, 5, 6}

# Methods
a.add(5)        # add element
a.discard(10)   # remove if present (no error)
a.remove(1)     # remove (KeyError if missing)
a.update([6, 7]) # add multiple

# Membership test (O(1) - faster than list)
print(3 in a)   # True

# Frozen set (immutable)
fs = frozenset([1, 2, 3])

# Common use: deduplicate
unique = list(set([1, 1, 2, 2, 3]))  # [1, 2, 3]

推导式

推导式是简洁地创建集合的 Pythonic 方式。生成器表达式(用括号代替方括号)是惰性的——它们按需产生值,节省内存。为提高可读性,优先使用推导式而非 map()/filter()。

python
# List comprehension
squares = [x**2 for x in range(10)]
evens = [x for x in range(20) if x % 2 == 0]
pairs = [(x, y) for x in range(3) for y in range(3)]

# Dict comprehension
square_map = {x: x**2 for x in range(5)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

# Set comprehension
unique_lens = {len(w) for w in ["a", "ab", "abc", "ab"]}

# Generator expression (lazy, memory-efficient)
gen = (x**2 for x in range(1000000))
print(next(gen))  # 0
print(next(gen))  # 1
total = sum(x**2 for x in range(100))  # no extra list

# Nested comprehension (matrix)
matrix = [[i * 3 + j for j in range(3)] for i in range(3)]
# [[0,1,2], [3,4,5], [6,7,8]]

Collections 模块

collections 模块提供专用容器。Counter 计数可哈希项。defaultdict 自动创建缺失的键。deque 在两端提供 O(1) 的追加/弹出(列表为 O(n))。这些对于编写简洁高效的代码至关重要。

python
from collections import Counter, defaultdict, deque, OrderedDict

# Counter - counting
words = ["apple", "banana", "apple", "cherry", "banana", "apple"]
cnt = Counter(words)
print(cnt)  # Counter({'apple': 3, 'banana': 2, 'cherry': 1})
print(cnt.most_common(2))  # [('apple', 3), ('banana', 2)]

# defaultdict - no KeyError
dd = defaultdict(list)
dd["fruits"].append("apple")
dd["fruits"].append("banana")
# dd["vegs"] automatically creates empty list

# deque - fast double-ended queue
dq = deque([1, 2, 3])
dq.appendleft(0)   # [0, 1, 2, 3]
dq.append(4)       # [0, 1, 2, 3, 4]
dq.popleft()       # 0, deque is now [1, 2, 3, 4]
dq.rotate(1)       # rotate right

# OrderedDict (less needed since 3.7, dicts are ordered)
od = OrderedDict([("a", 1), ("b", 2)])
06

控制流

If / Elif / Else

Python 使用 if/elif/else——注意是 'elif' 不是 'elseif'。缩进定义代码块。三元运算符 'x if cond else y' 是一个表达式。Python 将空集合、0、None 和 False 视为假值——对于简洁的条件语句很有用。

python
score = 85

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
else:
    grade = "F"

print(f"Grade: {grade}")  # Grade: B

# Conditional expression (ternary)
status = "pass" if score >= 60 else "fail"

# Truthy/falsy values
# Falsy: False, 0, 0.0, "", [], {}, (), None
# Everything else is truthy
if []:    # False
    print("never")
if [0]:   # True (non-empty list)
    print("always")

For 循环与迭代

Python 的 for 循环遍历任何可迭代对象。range() 生成数字(stop 是排他的)。enumerate() 将项与索引配对。zip() 并行迭代多个序列。使用 .items() 迭代字典的键值对。

python
# range(start, stop, step)
for i in range(5):        # 0, 1, 2, 3, 4
    print(i)
for i in range(2, 10, 2): # 2, 4, 6, 8
    print(i)
for i in range(10, 0, -1): # countdown
    print(i)

# Iterate over collections
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
    print(fruit)

# enumerate for index + value
for idx, fruit in enumerate(fruits):
    print(f"{idx}: {fruit}")

# zip to iterate multiple sequences
names = ["Alice", "Bob"]
ages = [30, 25]
for name, age in zip(names, ages):
    print(f"{name}: {age}")

# Iterate dict
user = {"name": "Alice", "age": 30}
for key, value in user.items():
    print(f"{key} = {value}")

While 循环与 Break/Continue

while 循环在条件为真时重复。break 立即退出循环,continue 跳到下一次迭代。for/else 结构仅在循环未被 break 时运行 else 块。pass 是空块的空操作占位符。

python
# Basic while
count = 0
while count < 5:
    print(count)
    count += 1

# break - exit loop
while True:
    cmd = input("> ")
    if cmd == "quit":
        break
    print(f"You said: {cmd}")

# continue - skip to next iteration
for i in range(10):
    if i % 2 == 0:
        continue  # skip even numbers
    print(i)  # prints 1, 3, 5, 7, 9

# else clause (runs if no break)
for i in range(5):
    if i == 10:
        break
else:
    print("Loop completed without break")

# pass - do nothing (placeholder)
for i in range(5):
    pass  # TODO: implement

Match 语句(Python 3.10+)

match 语句(Python 3.10+)是强大的结构化模式匹配,远超 C 的 switch。它可以匹配序列、映射、类实例并绑定变量。_ 模式是通配符(默认值)。使用 'if' 的守卫添加条件。

python
# Structural pattern matching (like switch)
def handle_command(cmd):
    match cmd.split():
        case ["quit"]:
            return "Goodbye"
        case ["hello", name]:
            return f"Hello, {name}!"
        case ["move", direction] if direction in "NSEW":
            return f"Moving {direction}"
        case ["add", x, y]:
            return int(x) + int(y)
        case _:
            return "Unknown command"

print(handle_command("hello Alice"))  # Hello, Alice!

# Matching data structures
match point:
    case (0, 0):
        print("origin")
    case (0, y):
        print(f"on y-axis at {y}")
    case (x, 0):
        print(f"on x-axis at {x}")
    case (x, y):
        print(f"at ({x}, {y})")

迭代器与生成器

生成器使用 yield 惰性产生值——它们不会预先计算所有值,节省内存。它们实现迭代器协议(iter() 和 next())。一旦耗尽,就结束了。将生成器用于大型/无限序列、管道和流数据。

python
# Iterator protocol
nums = [1, 2, 3]
it = iter(nums)
print(next(it))  # 1
print(next(it))  # 2
print(next(it))  # 3
# next(it)  # StopIteration

# Generator function (uses yield)
def count_up_to(n):
    count = 1
    while count <= n:
        yield count
        count += 1

for num in count_up_to(5):
    print(num)  # 1, 2, 3, 4, 5

# Infinite generator
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fib = fibonacci()
print(next(fib))  # 0
print(next(fib))  # 1
print(next(fib))  # 1
print(next(fib))  # 2

# Generator expression
squares = (x**2 for x in range(10))
07

函数

定义与调用函数

函数用 def 定义。默认参数使用 =。Python 支持关键字参数以提高清晰度。函数可以返回多个值(作为元组)。文档字符串(三引号)记录函数,可通过 help() 访问。

python
# Basic function
def greet(name):
    return f"Hello, {name}!"

print(greet("Alice"))  # Hello, Alice!

# Default arguments
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

print(greet("Bob"))              # Hello, Bob!
print(greet("Bob", "Hi"))        # Hi, Bob!

# Keyword arguments
print(greet(name="Carol", greeting="Hey"))

# Return multiple values (tuple)
def stats(nums):
    return min(nums), max(nums), sum(nums) / len(nums)

lo, hi, avg = stats([1, 2, 3, 4, 5])

# Docstrings
def add(a, b):
    """Add two numbers and return the result.
    
    Args:
        a: First number
        b: Second number
    Returns:
        Sum of a and b
    """
    return a + b

参数:*args 与 **kwargs

*args 将额外的位置参数收集到元组中,**kwargs 将额外的关键字参数收集到字典中。名称 args/kwargs 是约定俗成的。调用函数时可以用 * 解包序列,用 ** 解包字典。顺序:位置参数、*args、关键字参数、**kwargs。

python
# *args - variable positional arguments (tuple)
def sum_all(*args):
    return sum(args)

print(sum_all(1, 2, 3))       # 6
print(sum_all(1, 2, 3, 4, 5)) # 15

# **kwargs - variable keyword arguments (dict)
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=30, role="admin")

# Combining all
def func(a, b, *args, **kwargs):
    print(f"a={a}, b={b}")
    print(f"args={args}")
    print(f"kwargs={kwargs}")

func(1, 2, 3, 4, x=5, y=6)
# a=1, b=2, args=(3, 4), kwargs={'x': 5, 'y': 6}

# Unpacking arguments
nums = [1, 2, 3]
print(sum_all(*nums))  # unpack list as args

opts = {"name": "Alice", "age": 30}
print_info(**opts)  # unpack dict as kwargs

Lambda 与高阶函数

Lambda 仅限于单个表达式——复杂逻辑请使用 def。它们作为参数传递给 sorted()、map()、filter() 等高阶函数时表现出色。然而,列表推导式通常比 map/filter 更易读。reduce() 位于 functools 中。

python
# Lambda - anonymous function (single expression)
square = lambda x: x ** 2
print(square(5))  # 25

# Common with sorted, map, filter, reduce
students = [("Alice", 85), ("Bob", 92), ("Carol", 78)]

# Sort by score (key function)
sorted_by_score = sorted(students, key=lambda s: s[1])
# [('Carol', 78), ('Alice', 85), ('Bob', 92)]

# map - apply function to each item
nums = [1, 2, 3, 4, 5]
doubled = list(map(lambda x: x * 2, nums))
# [2, 4, 6, 8, 10]

# filter - keep items where function returns True
evens = list(filter(lambda x: x % 2 == 0, nums))
# [2, 4]

# reduce - accumulate to single value
from functools import reduce
product = reduce(lambda a, b: a * b, nums)
# 120 (1*2*3*4*5)

# Prefer comprehensions over map/filter
doubled = [x * 2 for x in nums]  # more Pythonic
evens = [x for x in nums if x % 2 == 0]

装饰器

装饰器包装函数以在不修改原始代码的情况下添加行为。@语法是语法糖。带参数的装饰器需要额外的嵌套层级。始终使用 functools.wraps 保留原始函数的元数据(名称、文档字符串)。

python
# A decorator modifies a function's behavior
def uppercase_result(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()
    return wrapper

@uppercase_result
def greet(name):
    return f"hello, {name}"

print(greet("alice"))  # HELLO, ALICE

# Decorator with arguments
def repeat(times):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(3)
def say_hi():
    print("Hi!")

say_hi()  # prints "Hi!" three times

# Practical: timing decorator
import time
def timer(func):
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} took {time.time() - start:.4f}s")
        return result
    return wrapper

# Use functools.wraps to preserve metadata
from functools import wraps
def my_decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

作用域与闭包

Python 使用 LEGB 作用域顺序解析名称:Local(局部)、Enclosing(嵌套)、Global(全局)、Built-in(内置)。使用 'global' 在函数内重新绑定全局变量。使用 'nonlocal'(Python 3)修改嵌套作用域中的变量。闭包记住其封闭作用域。

python
# LEGB rule: Local, Enclosing, Global, Built-in
x = "global"

def outer():
    x = "enclosing"
    
    def inner():
        x = "local"
        print(x)  # local
    
    inner()
    print(x)  # enclosing

outer()
print(x)  # global

# global keyword - modify global variable
count = 0
def increment():
    global count
    count += 1

# nonlocal keyword - modify enclosing variable
def make_counter():
    count = 0
    def counter():
        nonlocal count
        count += 1
        return count
    return counter

c = make_counter()
print(c())  # 1
print(c())  # 2
print(c())  # 3
08

OOP 与类

类与对象

类将数据(属性)和行为(方法)捆绑在一起。__init__ 是构造函数。self 指向实例(类似其他语言中的 'this')。类变量是共享的;实例变量是每个对象独有的。__str__ 面向用户,__repr__ 面向开发者。

python
class Dog:
    # Class variable (shared by all instances)
    species = "Canis familiaris"
    
    # Constructor
    def __init__(self, name, age):
        # Instance variables
        self.name = name
        self.age = age
    
    # Instance method
    def bark(self):
        return f"{self.name} says Woof!"
    
    # String representation
    def __str__(self):
        return f"Dog({self.name}, {self.age})"
    
    # Official representation (for debugging)
    def __repr__(self):
        return f"Dog(name='{self.name}', age={self.age})"

# Create instances
buddy = Dog("Buddy", 3)
lucy = Dog("Lucy", 5)

print(buddy.bark())       # Buddy says Woof!
print(buddy.name)         # Buddy
print(buddy.species)      # Canis familiaris
print(str(buddy))         # Dog(Buddy, 3)

继承与多态

继承让类重用和扩展行为。Python 支持多重继承,使用 MRO(方法解析顺序)解决冲突。多态允许统一对待不同类型。使用 isinstance() 进行类型检查,而不是 type()。

python
class Animal:
    def __init__(self, name):
        self.name = name
    
    def speak(self):
        raise NotImplementedError("Subclass must implement")

class Dog(Animal):
    def speak(self):
        return f"{self.name} says Woof!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says Meow!"

# Polymorphism - same interface, different behavior
def animal_sound(animal):
    print(animal.speak())

animals = [Dog("Buddy"), Cat("Whiskers")]
for a in animals:
    animal_sound(a)
# Buddy says Woof!
# Whiskers says Meow!

# Multiple inheritance
class Swimmer:
    def swim(self):
        return "swimming"

class Flyer:
    def fly(self):
        return "flying"

class Duck(Animal, Swimmer, Flyer):
    pass

duck = Duck("Donald")
print(duck.swim())  # swimming
print(duck.fly())   # flying

# Check inheritance
print(isinstance(duck, Animal))  # True
print(issubclass(Dog, Animal))   # True

属性与封装

Python 没有真正的 private/protected——它使用约定。单下划线 _ 表示“内部”。双下划线 __ 触发名称改写(不是真正的私有)。@property 将方法变为带 getter/setter 的属性,支持验证和计算属性。

python
class Temperature:
    def __init__(self, celsius=0):
        self.celsius = celsius  # uses setter below
    
    # Getter
    @property
    def celsius(self):
        return self._celsius
    
    # Setter
    @celsius.setter
    def celsius(self, value):
        if value < -273.15:
            raise ValueError("Below absolute zero!")
        self._celsius = value
    
    # Computed property
    @property
    def fahrenheit(self):
        return self._celsius * 9/5 + 32
    
    @fahrenheit.setter
    def fahrenheit(self, value):
        self.celsius = (value - 32) * 5/9

temp = Temperature(25)
print(temp.fahrenheit)  # 77.0
temp.fahrenheit = 100
print(temp.celsius)     # 37.78...

# Name conventions:
# _name   - protected (convention, not enforced)
# __name  - private (name mangling: _ClassName__name)
# __name__ - dunder (reserved by Python)

类方法与静态方法

@staticmethod 只是类命名空间中的一个函数——没有隐式的第一个参数。@classmethod 接收类(cls)作为第一个参数,适用于替代构造函数(工厂方法)和继承感知行为。构造函数用 classmethod,工具函数用 staticmethod。

python
class MathUtils:
    pi = 3.14159
    
    # Static method - no self/cls, lives in class namespace
    @staticmethod
    def add(a, b):
        return a + b
    
    # Class method - receives the class as first argument
    @classmethod
    def circle_area(cls, radius):
        return cls.pi * radius ** 2
    
    # Alternative constructor (common classmethod use)
    @classmethod
    def from_diameter(cls, diameter):
        return cls()  # would configure instance

# Static: called on class or instance, no special first arg
print(MathUtils.add(2, 3))  # 5

# Class: often used for alternative constructors
print(MathUtils.circle_area(5))  # 78.54...

# Factory pattern with classmethod
class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    @classmethod
    def origin(cls):
        return cls(0, 0)
    
    @classmethod
    def from_tuple(cls, coords):
        return cls(*coords)

p1 = Point.origin()
p2 = Point.from_tuple((3, 4))

魔术方法(Dunder)

魔术方法(dunder 方法)实现运算符重载和协议行为。__add__ 对应 +,__eq__ 对应 ==,__len__ 对应 len(),__iter__ 对应迭代/解包。它们让你的对象自然地使用 Python 的内置语法和函数。

python
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    # String representation
    def __str__(self):
        return f"Vector({self.x}, {self.y})"
    
    # Operator overloading
    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)
    
    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)
    
    # Equality
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
    
    # Length
    def __len__(self):
        return int((self.x**2 + self.y**2) ** 0.5)
    
    # Make it iterable
    def __iter__(self):
        yield self.x
        yield self.y
    
    # Index access
    def __getitem__(self, index):
        return (self.x, self.y)[index]

v1 = Vector(2, 3)
v2 = Vector(4, 5)
print(v1 + v2)        # Vector(6, 8)
print(v1 * 3)         # Vector(6, 9)
print(v1 == Vector(2, 3))  # True
print(len(v1))        # 3
x, y = v1             # unpacking via __iter__
09

错误处理

Try / Except / Finally

try/except/else/finally:try 运行有风险的代码,except 捕获错误,else 在无异常时运行,finally 始终运行(清理)。捕获特定异常,而不是裸 'except:'。当清理应仅在成功时发生时,else 块很有用。Exception 是大多数可捕获错误的基类。

python
# Basic exception handling
try:
    result = 10 / 0
except ZeroDivisionError as e:
    print(f"Error: {e}")  # division by zero
finally:
    print("This always runs")

# Multiple exception types
try:
    value = int("abc")
except (ValueError, TypeError) as e:
    print(f"Conversion error: {e}")

# Different handlers for different exceptions
try:
    f = open("nonexistent.txt")
    data = f.read()
except FileNotFoundError:
    print("File not found")
except PermissionError:
    print("No permission")
except Exception as e:
    print(f"Unexpected: {e}")
else:
    print("No exception occurred")
    f.close()
finally:
    print("Cleanup (always runs)")

# Exception hierarchy
# BaseException
#  ├── SystemExit
#  ├── KeyboardInterrupt
#  └── Exception
#       ├── ValueError
#       ├── TypeError
#       ├── KeyError
#       └── ...

抛出异常

使用 raise 抛出异常。单独的 'raise' 重新抛出当前异常(在 except 块中)。'raise X from Y' 链接异常,保留原始原因。始终抛出特定的异常类型。避免将异常用于正常的控制流。

python
# Raise an exception
def divide(a, b):
    if b == 0:
        raise ZeroDivisionError("Cannot divide by zero!")
    return a / b

# Re-raise the current exception
def process(data):
    try:
        return parse(data)
    except ValueError:
        print("Logging parse error...")
        raise  # re-raises the same exception

# Raise with context (from)
try:
    int("abc")
except ValueError as e:
    raise RuntimeError("Failed to process input") from e

# Common built-in exceptions
raise ValueError("invalid value")
raise TypeError("wrong type")
raise KeyError("missing key")
raise IndexError("out of range")
raise RuntimeError("something went wrong")
raise NotImplementedError("override this")
raise FileNotFoundError("no such file")

# Exception with custom args
class ValidationError(Exception):
    pass

raise ValidationError("field is required", "email")

自定义异常

通过继承 Exception(或更具体的内置异常)创建自定义异常。设计层次结构,让调用者能在合适的级别捕获。添加自定义属性以携带上下文。从 Exception 继承,而不是 BaseException(后者包括 SystemExit/KeyboardInterrupt)。

python
# Custom exception hierarchy
class AppError(Exception):
    """Base exception for the application."""
    pass

class DatabaseError(AppError):
    def __init__(self, message, query=None):
        super().__init__(message)
        self.query = query

class ValidationError(AppError):
    def __init__(self, field, message):
        super().__init__(f"{field}: {message}")
        self.field = field
        self.message = message

class AuthenticationError(AppError):
    pass

# Usage
def login(username, password):
    if not username:
        raise ValidationError("username", "is required")
    if password != "secret":
        raise AuthenticationError("Invalid credentials")

# Catching by hierarchy
try:
    login("", "x")
except ValidationError as e:
    print(f"Validation failed: {e.field}")
except AppError as e:
    print(f"App error: {e}")

# Access exception info
import traceback
try:
    1 / 0
except:
    traceback.print_exc()
    print(repr(sys.exc_info()[1]))

上下文管理器(with 语句)

上下文管理器('with' 语句)通过 __enter__ 和 __exit__ 保证清理。它们对于文件、锁和数据库连接等资源至关重要。contextlib.contextmanager 使用生成器简化创建。__exit__ 可以通过返回 True 抑制异常。

python
# Context managers handle setup and cleanup
with open("file.txt") as f:
    content = f.read()
# file is automatically closed, even if an error occurs

# Multiple context managers
with open("input.txt") as fin, open("output.txt", "w") as fout:
    fout.write(fin.read())

# Creating a context manager (class-based)
class Timer:
    def __enter__(self):
        import time
        self.start = time.time()
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        import time
        self.elapsed = time.time() - self.start
        print(f"Elapsed: {self.elapsed:.4f}s")
        return False  # don't suppress exceptions

with Timer() as t:
    # code to time
    sum(range(1000000))

# contextlib for simpler context managers
from contextlib import contextmanager

@contextmanager
def open_db(url):
    db = connect(url)
    try:
        yield db
    finally:
        db.close()

with open_db("localhost") as db:
    db.query("SELECT 1")

断言与日志

assert 语句用于调试不变量——当 Python 以 -O(优化)运行时会被剥离。永远不要用断言进行输入验证。在生产代码中使用 logging 模块代替 print()——它支持级别、格式化和输出目标。

python
# Assertions - for debugging (removed with -O flag)
def divide(a, b):
    assert b != 0, "Divisor cannot be zero"
    return a / b

# Never use assertions for data validation (they can be disabled)
# Use them for invariant checks during development

# Logging (better than print for production)
import logging

# Configure logging
logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s [%(levelname)s] %(message)s"
)

logger = logging.getLogger(__name__)

logger.debug("Detailed info for debugging")
logger.info("Confirmation things are working")
logger.warning("Something unexpected happened")
logger.error("A serious problem")
logger.critical("A fatal error")

# Log exceptions with traceback
try:
    1 / 0
except:
    logger.exception("Failed to divide")  # includes traceback
10

文件 I/O

读取文件

始终使用 'with' 打开文件——即使发生错误也会自动关闭。指定 encoding='utf-8' 以避免平台相关的编码问题。对于大文件,逐行迭代而不是 read() 以节省内存。readlines() 将整个文件加载到内存。

python
# Read entire file
with open("file.txt", "r", encoding="utf-8") as f:
    content = f.read()
    print(content)

# Read line by line (memory-efficient for large files)
with open("file.txt", "r") as f:
    for line in f:
        print(line.strip())  # strip removes trailing newline

# Read all lines into a list
with open("file.txt") as f:
    lines = f.readlines()  # ['line1\n', 'line2\n', ...]

# Read specific number of characters
with open("file.txt") as f:
    chunk = f.read(100)  # first 100 chars

# File modes:
# "r"  read (default)
# "w"  write (truncate)
# "a"  append
# "x"  exclusive create (fails if exists)
# "b"  binary mode (e.g., "rb", "wb")
# "+"  read and write (e.g., "r+")

写入文件

模式 'w' 截断文件(删除内容);使用 'a' 追加。writelines() 不添加换行符——需手动添加。二进制文件(图像等)使用 'rb'/'wb'。seek() 移动光标;tell() 返回其位置。文本文件始终指定编码。

python
# Write text (overwrites existing)
with open("output.txt", "w") as f:
    f.write("First line\n")
    f.write("Second line\n")
    
    # writelines doesn't add newlines
    f.writelines(["line3\n", "line4\n"])

# Append to a file
with open("log.txt", "a") as f:
    f.write("New log entry\n")

# Write binary data
with open("data.bin", "wb") as f:
    f.write(b"\x00\x01\x02\x03")

# Read and write simultaneously
with open("file.txt", "r+") as f:
    content = f.read()
    f.seek(0)           # move to beginning
    f.write("Updated")  # overwrite
    f.truncate()        # cut off remaining

# Check if file exists
import os
if os.path.exists("file.txt"):
    print("File exists")

路径处理(pathlib)

pathlib(Python 3.4+)是现代的、面向对象的路径处理方式——优先使用它而非 os.path。/ 运算符以平台无关的方式连接路径。Path 对象有 read_text()/write_text() 方法为你处理打开/关闭。rglob() 递归搜索。

python
from pathlib import Path

# Create Path objects (preferred over os.path)
p = Path("src/main.py")
home = Path.home()           # /home/user or C:\Users\user
cwd = Path.cwd()             # current working directory

# Path components
print(p.name)        # main.py
print(p.stem)        # main
print(p.suffix)      # .py
print(p.parent)      # src
print(p.parts)       # ('src', 'main.py')

# Joining paths (use / operator)
config = home / ".config" / "app" / "config.json"

# Existence and type
print(p.exists())    # True/False
print(p.is_file())
print(p.is_dir())

# Listing directories
for f in Path(".").iterdir():
    print(f)

# Glob patterns
for py_file in Path(".").rglob("*.py"):
    print(py_file)

# Create directories
Path("new/dir").mkdir(parents=True, exist_ok=True)

# Read/write (Path methods)
content = Path("file.txt").read_text()
Path("output.txt").write_text("Hello!")

JSON

json.dumps() 序列化为字符串,json.loads() 反序列化。dump()/load() 处理文件。使用 indent 进行美化打印。自定义对象需要默认序列化器。JSON 仅支持基本类型——对 datetime 和其他复杂对象使用 default=。

python
import json

# Python dict to JSON string
data = {"name": "Alice", "age": 30, "skills": ["Python", "SQL"]}
json_str = json.dumps(data, indent=2)
print(json_str)

# JSON string to Python dict
parsed = json.loads('{"name": "Bob", "active": true}')
print(parsed["name"])  # Bob
print(parsed["active"])  # True (Python bool)

# Write JSON to file
with open("data.json", "w") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)

# Read JSON from file
with open("data.json") as f:
    loaded = json.load(f)

# Custom serialization (e.g., datetime)
from datetime import datetime
def json_default(obj):
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError

json.dumps({"time": datetime.now()}, default=json_default)

# Type mapping:
# JSON object  <-> Python dict
# JSON array   <-> Python list
# JSON string  <-> Python str
# JSON number  <-> Python int/float
# JSON boolean <-> Python bool
# JSON null    <-> Python None

CSV 与其他格式

csv 模块以正确的引用处理 CSV。在 Windows 上打开 CSV 文件时使用 newline=''。DictReader/DictWriter 按列名操作。pickle 可以序列化任何 Python 对象,但是 Python 特定的且不安全——永远不要反序列化来自不受信任来源的数据。

python
import csv

# Write CSV
with open("data.csv", "w", newline="") as f:
    writer = csv.writer(f)
    writer.writerow(["name", "age", "city"])
    writer.writerows([
        ["Alice", 30, "NYC"],
        ["Bob", 25, "LA"],
    ])

# Read CSV
with open("data.csv") as f:
    reader = csv.reader(f)
    header = next(reader)  # first row
    for row in reader:
        print(row)  # ['Alice', '30', 'NYC']

# DictReader/DictWriter (column access by name)
with open("data.csv") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], row["age"])

# Pickle (Python-specific, can store any object)
import pickle
with open("data.pkl", "wb") as f:
    pickle.dump({"complex": [1, 2, {"a": 3}]}, f)

with open("data.pkl", "rb") as f:
    obj = pickle.load(f)

# WARNING: pickle is insecure - never unpickle untrusted data!
11

模块与包

导入模块

导入引入模块。'import X' 保持命名空间整洁。'from X import Y' 方便但可能导致名称冲突。别名(import X as Y)对于有约定的库很常见(np、pd)。避免 'from X import *'——它会污染命名空间。

python
# Import entire module
import math
print(math.sqrt(16))

# Import specific names
from datetime import datetime, timedelta
now = datetime.now()

# Import with alias
import numpy as np
import pandas as pd

# Import all names (discouraged - pollutes namespace)
# from os import *

# Conditional import (try/except)
try:
    import cjson as json
except ImportError:
    import json

# Check what's in a module
import os
print(dir(os))         # list all attributes
print(os.__file__)     # module location
print(os.__name__)     # module name

# Reload a module (during development)
import importlib
importlib.reload(my_module)

创建模块与包

模块是 .py 文件;包是带有 __init__.py 的目录。__init__.py 文件可以为空或设置包。__init__.py 中的 __all__ 控制 'from package import *' 导出什么。现代 Python(3.3+)支持没有 __init__.py 的命名空间包。

python
# A module is just a .py file
# mymath.py
def add(a, b):
    return a + b

PI = 3.14159

# A package is a directory with __init__.py
# mypackage/
#   __init__.py
#   module1.py
#   module2.py
#   subpackage/
#     __init__.py
#     module3.py

# __init__.py can be empty or contain package initialization
# mypackage/__init__.py
from .module1 import ClassA
from .module2 import func_b
__version__ = "1.0.0"
__all__ = ["ClassA", "func_b"]

# Using the package
from mypackage import ClassA
from mypackage.subpackage import module3

# __all__ controls 'from package import *'
# Without __all__, * imports only what's in __init__.py

__name__ == '__main__'

if __name__ == '__main__' 惯用法让文件既可作为脚本又可作为模块。直接运行时,__name__ 是 '__main__';被导入时,它是模块名。此模式对于创建可重用且可独立执行的模块至关重要。

python
# script.py
def main():
    print("Running main")

def helper():
    print("Helper function")

if __name__ == "__main__":
    # This code only runs when the file is executed directly
    # NOT when imported as a module
    main()

# When you run: python script.py
# __name__ is "__main__" -> main() runs

# When you: import script
# __name__ is "script" -> main() does NOT run
# This lets the module be both a script and an importable library

# Common pattern for CLI tools
def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("--name", required=True)
    args = parser.parse_args()
    print(f"Hello, {args.name}!")

if __name__ == "__main__":
    main()

标准库亮点

Python 的标准库庞大且“开箱即用”。os/sys 用于系统交互,datetime 用于日期,collections 用于专用容器,itertools 用于迭代器工具,functools 用于函数式编程。在 docs.python.org/3/library/ 探索文档。

python
# os - operating system interface
import os
os.getcwd()           # current directory
os.listdir(".")       # list files
os.environ.get("HOME")  # environment variables

# sys - system-specific
import sys
sys.argv              # command-line arguments
sys.exit(0)           # exit with status code
sys.path              # module search path

# datetime - date and time
from datetime import datetime, timedelta
now = datetime.now()

# collections - specialized containers
from collections import Counter, defaultdict, deque

# itertools - iterator tools
from itertools import chain, cycle, repeat, product

# functools - higher-order functions
from functools import lru_cache, reduce, partial

# typing - type hints
from typing import List, Dict, Optional, Union, Any

# pathlib - path handling
from pathlib import Path

# subprocess - run external commands
import subprocess
result = subprocess.run(["ls", "-l"], capture_output=True, text=True)

Pip 与虚拟环境

始终使用虚拟环境隔离项目依赖。venv 是内置的;替代方案包括 virtualenv、conda 和 uv。在 requirements.txt 中固定版本以实现可复现。永远不要使用 --user 或以 root 身份全局安装包——使用 venv。

python
# Create a virtual environment
# $ python -m venv venv

# Activate it
# Windows: venv\Scripts\activate
# Unix:    source venv/bin/activate

# Install packages
# $ pip install requests
# $ pip install requests==2.28.0
# $ pip install "requests>=2.25,<3.0"

# Install from requirements file
# $ pip install -r requirements.txt

# requirements.txt example:
# requests==2.31.0
# numpy>=1.21.0
# pandas~=2.0.0  # compatible release

# List installed packages
# $ pip list
# $ pip freeze > requirements.txt

# Uninstall
# $ pip uninstall requests

# Show package info
# $ pip show requests

# Modern alternative: uv (faster)
# $ uv pip install requests
12

日期与时间

datetime 模块

datetime 模块提供 date、time、datetime 和 timedelta 类。datetime.now() 返回本地时间;使用 datetime.now(timezone.utc) 获取 UTC。weekday() 返回 0-6(周一到周日)。在生产中始终使用时区感知的 datetime 以避免歧义。

python
from datetime import datetime, date, time, timedelta

# Current date and time
now = datetime.now()          # local time
utc_now = datetime.utcnow()   # UTC (deprecated in 3.12)
utc = datetime.now(timezone.utc)  # preferred

# Current date
today = date.today()

# Create specific date/time
dt = datetime(2024, 1, 15, 10, 30, 0)
d = date(2024, 1, 15)
t = time(10, 30, 0)

# Access components
print(now.year, now.month, now.day)
print(now.hour, now.minute, now.second)
print(now.weekday())  # 0=Monday, 6=Sunday

# From timestamp
ts = 1705315200
dt = datetime.fromtimestamp(ts)

# To timestamp
print(datetime.now().timestamp())

格式化与解析

strftime(字符串格式化时间)将 datetime 转换为字符串;strptime(字符串解析时间)将字符串转换为 datetime。ISO 8601 格式(isoformat/fromisoformat)是存储日期的最佳选择——它明确且可排序。记住常用代码:%Y %m %d %H %M %S。

python
from datetime import datetime

# Format datetime to string (strftime)
dt = datetime(2024, 1, 15, 10, 30)
print(dt.strftime("%Y-%m-%d"))         # 2024-01-15
print(dt.strftime("%Y/%m/%d %H:%M"))   # 2024/01/15 10:30
print(dt.strftime("%B %d, %Y"))        # January 15, 2024
print(dt.strftime("%A"))               # Monday

# Parse string to datetime (strptime)
dt = datetime.strptime("2024-01-15", "%Y-%m-%d")
dt = datetime.strptime("15/01/2024 10:30", "%d/%m/%Y %H:%M")

# Common format codes:
# %Y  year (2024)     %m  month (01)
# %d  day (15)        %H  hour (14)
# %M  minute (30)     %S  second (00)
# %B  month name      %b  month abbrev
# %A  weekday name    %a  weekday abbrev
# %I  12-hour         %p  AM/PM
# %j  day of year     %U  week number

# ISO format (recommended for storage)
iso = dt.isoformat()  # "2024-01-15T10:30:00"
dt = datetime.fromisoformat("2024-01-15T10:30:00")

timedelta 与算术

timedelta 表示持续时间。可以从 datetime 加减 timedelta,两个 datetime 相减得到 timedelta。timedelta 会规范化:days=1, hours=25 变为 days=2, hours=1。total_seconds() 给出以秒为单位的整个持续时间。

python
from datetime import datetime, timedelta

now = datetime.now()

# Add/subtract time
tomorrow = now + timedelta(days=1)
last_week = now - timedelta(weeks=1)
in_2_hours = now + timedelta(hours=2)
in_90_days = now + timedelta(days=90)

# Difference between dates
date1 = datetime(2024, 1, 15)
date2 = datetime(2024, 6, 18)
diff = date2 - date1
print(diff.days)         # 155
print(diff.total_seconds())

# timedelta components
td = timedelta(days=5, hours=3, minutes=30)
print(td.days)           # 5
print(td.seconds)        # 12600 (3h 30m in seconds)
print(td.total_seconds())

# Comparisons
if now > date1:
    print("now is later")

# Business day calculation (using numpy)
# import numpy as np
# business_days = np.busday_count(date1.date(), date2.date())

时区

始终使用时区感知的 datetime(Python 3.9+ 的 ZoneInfo 优于 pytz)。以 UTC 存储日期,仅在显示时转换为本地时间。朴素 datetime(不带 tzinfo)会导致难以察觉的 bug。ZoneInfo 使用 IANA 时区数据库,自动处理夏令时。

python
from datetime import datetime, timezone, timedelta

# Timezone-aware datetime
utc_time = datetime.now(timezone.utc)
print(utc_time)  # 2024-01-15 10:30:00+00:00

# Create a timezone (offset-based)
tz_ny = timezone(timedelta(hours=-5), "EST")
ny_time = datetime.now(tz_ny)

# Convert between timezones
utc_time = datetime.now(timezone.utc)
ny_time = utc_time.astimezone(timezone(timedelta(hours=-5)))
tokyo_time = utc_time.astimezone(timezone(timedelta(hours=9)))

# Use zoneinfo (Python 3.9+) for IANA timezones
from zoneinfo import ZoneInfo
tz = ZoneInfo("America/New_York")
dt = datetime.now(tz)
print(dt.tzname())  # EST or EDT

# Common IANA timezones:
# "UTC"
# "America/New_York", "America/Los_Angeles"
# "Europe/London", "Europe/Paris"
# "Asia/Tokyo", "Asia/Shanghai"
# "Australia/Sydney"

# Best practice: store UTC, convert for display
utc_stored = datetime.now(timezone.utc)
local_display = utc_stored.astimezone(ZoneInfo("Asia/Shanghai"))
13

正则表达式

re 模块基础

re.search() 在任意位置查找第一个匹配;re.match() 仅在开头;re.fullmatch() 要求整个字符串匹配。使用原始字符串(r'...')作为模式以避免反斜杠转义问题。匹配对象提供 group()、start()、end() 和 span()。

python
import re

# re.search - find first match anywhere in string
m = re.search(r"\d{4}", "Order #2024 was placed")
if m:
    print(m.group())  # 2024
    print(m.start(), m.end())  # 9 13

# re.match - match at beginning of string
m = re.match(r"Hello", "Hello, World")
print(m.group())  # Hello

# re.fullmatch - entire string must match
m = re.fullmatch(r"\d+", "12345")
print(bool(m))  # True

# re.findall - all matches as list
emails = re.findall(r"\S+@\S+", text)
numbers = re.findall(r"\d+", "a1b22c333")  # ['1', '22', '333']

# re.finditer - all matches as iterator (with positions)
for m in re.finditer(r"\w+", "Hello World"):
    print(m.group(), m.span())

# Match object methods
m = re.search(r"(\w+)@(\w+)", "[email protected]")
print(m.group())   # user@domain (whole match)
print(m.group(1))  # user (first group)
print(m.group(2))  # domain (second group)
print(m.groups())  # ('user', 'domain')

模式语法

正则表达式语法:[] 用于字符类,\d \w \s 用于常用集合,量词(* + ? {})用于重复,^ $ \b 用于锚点,() 用于分组,| 用于交替。使用原始字符串(r'...')使反斜杠成为字面量。贪婪量词尽可能多地匹配;添加 ? 使其变为惰性(例如 *?)。

python
import re

# Character classes
re.findall(r"[aeiou]", "hello")      # vowels
re.findall(r"[^aeiou]", "hello")     # non-vowels
re.findall(r"[a-z]", "Hello123")     # lowercase
re.findall(r"[A-Za-z0-9]", "Hi-1!")  # alphanumeric

# Predefined classes
# .   any char except newline
# \d  digit [0-9]      \D  non-digit
# \w  word char [a-zA-Z0-9_]  \W  non-word
# \s  whitespace       \S  non-whitespace

# Quantifiers
# *     0 or more
# +     1 or more
# ?     0 or 1
# {n}   exactly n
# {n,}  n or more
# {n,m} between n and m
re.findall(r"\d{3}", "1234567")      # ['123', '456']
re.findall(r"\d{2,4}", "12345678")   # ['1234', '5678']

# Anchors
# ^  start of string    $  end of string
# \b word boundary
re.findall(r"^\w+", "Hello World")   # ['Hello']
re.findall(r"\b\w+\b", "hi there") # ['hi', 'there']

# Groups & alternation
re.findall(r"(cat|dog)", "cat and dog")  # ['cat', 'dog']
re.findall(r"(\w+)@(\w+\.\w+)", "[email protected]")

替换与分割

re.sub() 替换匹配项——使用反向引用(\1、\2)引用分组,或使用函数进行动态替换。re.split() 比 str.split() 更强大——它接受正则表达式模式。模式中的捕获组会包含在结果中。使用 re.subn() 获取 (result, count)。

python
import re

# re.sub - replace matches
result = re.sub(r"\d+", "#", "a1b22c333")
# 'a#b#c#'

# Replace with count limit
result = re.sub(r"\d", "X", "a1b2c3", count=2)
# 'aXbXc3'

# Use backreferences in replacement
result = re.sub(r"(\w+)@(\w+)", r"\2.\1", "user@domain")
# 'domain.user'

# Use function as replacement
def upper(m):
    return m.group().upper()

result = re.sub(r"\b[a-z]", upper, "hello world")
# 'Hello World' (capitalize first letter of each word)

# re.split - split by pattern
parts = re.split(r"[,;\s]+", "a, b; c d")
# ['a', 'b', 'c', 'd']

# Split with capture groups (keeps delimiters)
parts = re.split(r"([,;])", "a,b;c")
# ['a', ',', 'b', ';', 'c']

# Split with maxsplit
parts = re.split(r",", "a,b,c,d", maxsplit=2)
# ['a', 'b', 'c,d']

编译与标志

当重复使用模式时用 re.compile() 编译——更快。标志修改行为:IGNORECASE、MULTILINE、DOTALL、VERBOSE(允许在模式中使用注释/空白)。命名组 (?P<name>...) 提高可读性。先行断言 (?=) 和后行断言 (?<=) 匹配但不消耗。

python
import re

# Compile pattern for reuse (faster when used many times)
email_re = re.compile(r"^[\w.+-]+@([\w-]+\.)+[\w-]+$")
print(email_re.match("[email protected]"))  # match object
print(email_re.match("invalid"))           # None

# Common flags
re.IGNORECASE  # case-insensitive
re.MULTILINE   # ^ and $ match line boundaries
re.DOTALL      # . matches newline too
re.VERBOSE     # allow whitespace & comments in pattern

# Combine flags with |
pattern = re.compile(r"""
    ^           # start of line
    (\w+)      # capture word
    \s+        # whitespace
    (\d+)      # capture number
""", re.VERBOSE | re.MULTILINE)

# Named groups (more readable)
m = re.match(r"(?P<year>\d{4})-(?P<month>\d{2})", "2024-01")
print(m.group("year"))   # 2024
print(m.group("month"))  # 01
print(m.groupdict())     # {'year': '2024', 'month': '01'}

# Lookahead/lookbehind
re.findall(r"\d+(?= dollars)", "100 dollars, 200 euros")
# ['100']  (positive lookahead)
re.findall(r"(?<=\$)\d+", "$100 and $200")
# ['100', '200']  (positive lookbehind)
14

异步与并发

asyncio 基础

asyncio 是 Python 的异步 I/O 框架。'async def' 定义协程;'await' 挂起直到结果就绪。asyncio.run() 启动事件循环。asyncio.gather() 并发运行协程。协程无需线程即可实现高并发 I/O。

python
import asyncio

# Define a coroutine
async def greet(name, delay):
    await asyncio.sleep(delay)  # non-blocking sleep
    return f"Hello, {name}!"

# Run a coroutine
async def main():
    result = await greet("Alice", 1)
    print(result)

# Run the event loop
asyncio.run(main())

# Concurrent execution with gather
async def main():
    # Run coroutines concurrently
    results = await asyncio.gather(
        greet("Alice", 2),
        greet("Bob", 1),
        greet("Carol", 3)
    )
    print(results)  # all complete after 3 seconds (max delay)

asyncio.run(main())

# asyncio.create_task - schedule without awaiting immediately
async def main():
    task = asyncio.create_task(greet("Alice", 1))
    # do other work here
    result = await task  # await when needed
    print(result)

异步 HTTP 与超时

asyncio.timeout()(Python 3.11+)取消耗时过长的操作。对于 HTTP,使用 aiohttp(异步)而非 requests(同步)。asyncio.Queue 实现生产者-消费者模式。异步适用于 I/O 密集型工作(网络、磁盘)——不适用于 CPU 密集型工作。

python
import asyncio

# Async timeout
async def fetch_with_timeout(url, timeout=5):
    try:
        async with asyncio.timeout(timeout):
            # simulate async operation
            await asyncio.sleep(2)
            return f"Data from {url}"
    except asyncio.TimeoutError:
        return "Request timed out"

# Using aiohttp (third-party) for HTTP
# import aiohttp
# 
# async def fetch(url):
#     async with aiohttp.ClientSession() as session:
#         async with session.get(url) as response:
#             return await response.text()

# Producer-consumer pattern
async def producer(queue):
    for i in range(5):
        await asyncio.sleep(0.1)
        await queue.put(f"item-{i}")
    await queue.put(None)  # sentinel

async def consumer(queue):
    while True:
        item = await queue.get()
        if item is None:
            break
        print(f"Processed: {item}")
        queue.task_done()

async def main():
    queue = asyncio.Queue()
    await asyncio.gather(producer(queue), consumer(queue))

asyncio.run(main())

线程

线程用于 I/O 密集型并发(网络、文件 I/O)。Python 的 GIL 阻止线程中真正的并行 CPU 执行。使用 Lock 保护共享状态免受竞态条件。对于 CPU 密集型工作,改用 multiprocessing。线程共享内存;进程不共享。

python
import threading
import time

# Basic threading
def worker(name, delay):
    print(f"Worker {name} starting")
    time.sleep(delay)
    print(f"Worker {name} done")

# Create and start threads
t1 = threading.Thread(target=worker, args=("A", 2))
t2 = threading.Thread(target=worker, args=("B", 1))
t1.start()
t2.start()

# Wait for threads to complete
t1.join()
t2.join()
print("All done")

# Thread with Lock (for shared state)
counter = 0
lock = threading.Lock()

def increment():
    global counter
    for _ in range(100000):
        with lock:  # acquire/release lock
            counter += 1

threads = [threading.Thread(target=increment) for _ in range(5)]
for t in threads: t.start()
for t in threads: t.join()
print(f"Counter: {counter}")  # 500000 (correct with lock)

多进程

多进程绕过 GIL 实现真正的 CPU 并行——每个进程有自己的 Python 解释器。使用 Pool 进行并行 map 操作。concurrent.futures 为线程和进程提供统一 API。在 Windows 上始终用 if __name__ == '__main__' 保护。

python
from multiprocessing import Process, Pool, Queue
import os

# Basic process
def worker(name):
    print(f"Process {name} PID: {os.getpid()}")

if __name__ == "__main__":
    p = Process(target=worker, args=("A",))
    p.start()
    p.join()

# Process pool for parallel work
def square(x):
    return x * x

if __name__ == "__main__":
    with Pool(4) as pool:  # 4 worker processes
        results = pool.map(square, range(10))
        print(results)  # [0, 1, 4, 9, ..., 81]
    
    # Asynchronous map
    with Pool(4) as pool:
        result = pool.map_async(square, range(10))
        print(result.get())  # blocks until done

# concurrent.futures (higher-level API)
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor

with ProcessPoolExecutor() as executor:
    results = list(executor.map(square, range(10)))

with ThreadPoolExecutor() as executor:
    futures = [executor.submit(square, i) for i in range(10)]
    results = [f.result() for f in futures]
15

装饰器

基础装饰器

装饰器包装函数以扩展或修改其行为而不更改原始源代码。@语法是将装饰器调用结果赋回函数名的语法糖。在包装器中使用 *args、**kwargs 使其适用于任何签名。

python
# A decorator is a function that takes a function and returns a new function
def uppercase_result(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        return result.upper()
    return wrapper

@uppercase_result
def greet(name):
    return f"hello, {name}"

print(greet("world"))  # HELLO, WORLD
# @uppercase_result is sugar for: greet = uppercase_result(greet)

functools.wraps(保留元数据)

没有 @wraps,被包装的函数会丢失原始的 __name__、__doc__ 和签名——调试工具和 help() 显示 'wrapper'。在装饰器中始终使用 @functools.wraps(func) 保留元数据。这几乎是通用的最佳实践。

python
from functools import wraps

def log_calls(func):
    @wraps(func)  # copies __name__, __doc__, __module__
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__}({args}, {kwargs})")
        return func(*args, **kwargs)
    return wrapper

@log_calls
def add(a, b):
    """Add two numbers."""
    return a + b

print(add.__name__)  # 'add' (not 'wrapper')
print(add.__doc__)   # 'Add two numbers.'
help(add)            # shows original docstring

带参数的装饰器

当装饰器接受参数时,需要三层嵌套:工厂(接受参数)、装饰器(接受函数)和包装器(接受调用参数)。@repeat(3) 先调用 repeat(3),返回装饰器,然后将其应用于函数。

python
# A decorator factory: returns the actual decorator
def repeat(times):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            result = None
            for _ in range(times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator

@repeat(times=3)
def say_hi(name):
    print(f"Hi, {name}!")

say_hi("Alice")
# Hi, Alice! (printed 3 times)

基于类的装饰器

类装饰器使用 __init__ 存储函数,使用 __call__ 拦截调用。当装饰器需要维护状态(如调用计数器或缓存)时,它们非常理想。类实例替换函数,因此调用它会触发 __call__。

python
class CountCalls:
    def __init__(self, func):
        self.func = func
        self.count = 0
        wraps(func)(self)  # preserve metadata

    def __call__(self, *args, **kwargs):
        self.count += 1
        print(f"{self.func.__name__} called {self.count} times")
        return self.func(*args, **kwargs)

@CountCalls
def say_hello():
    print("Hello!")

say_hello()  # count=1
say_hello()  # count=2
say_hello()  # count=3
print(say_hello.count)  # 3

内置装饰器(@property、@staticmethod、@classmethod)

@property 将方法变为计算属性(无需括号即可访问)。@classmethod 接收类作为第一个参数——非常适合替代构造函数。@staticmethod 不接收隐式第一个参数——只是恰好位于类命名空间中的函数。它们共同构成了 Pythonic OOP 的骨干。

python
class Circle:
    pi = 3.14159

    def __init__(self, radius):
        self._radius = radius

    @property
    def area(self):
        return Circle.pi * self._radius ** 2

    @property
    def radius(self):
        return self._radius

    @radius.setter
    def radius(self, value):
        if value < 0:
            raise ValueError("Radius cannot be negative")
        self._radius = value

    @classmethod
    def from_diameter(cls, diameter):
        return cls(diameter / 2)

    @staticmethod
    def is_valid_radius(r):
        return r >= 0

c = Circle(5)
print(c.area)              # 78.54 (no parentheses!)
c.radius = 10             # uses the setter
c2 = Circle.from_diameter(20)  # alternative constructor

堆叠装饰器

堆叠装饰器时,它们自底向上应用(最靠近函数的先运行),但在调用时自顶向下执行。所以 @bold 包装 @italic 包装 greet。结果像洋葱层一样嵌套。顺序很重要——颠倒它们会改变输出嵌套。

python
from functools import wraps

def bold(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return f"<b>{func(*args, **kwargs)}</b>"
    return wrapper

def italic(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        return f"<i>{func(*args, **kwargs)}</i>"
    return wrapper

@bold
@italic
def greet(name):
    return f"Hello, {name}"

print(greet("World"))
# <b><i>Hello, World</i></b>
# Applied bottom-up: italic first, then bold
16

生成器与迭代器

生成器函数(yield)

生成器使用 yield 惰性产生值——它们在每个 yield 后暂停执行,在调用 next() 时恢复。这使它们对于大型或无限序列具有内存效率,因为一次只在内存中存在一个值。一旦耗尽,生成器无法重用。

python
# A generator uses 'yield' to produce values lazily, one at a time
def count_up_to(n):
    count = 1
    while count <= n:
        yield count
        count += 1

gen = count_up_to(5)
print(next(gen))  # 1
print(next(gen))  # 2
print(list(gen))  # [3, 4, 5] (exhausts the rest)

# Generators are memory-efficient: they don't build the whole list
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

fib = fibonacci()
print([next(fib) for _ in range(10)])
# [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

生成器表达式

生成器表达式是列表推导式的惰性等价物——使用括号而非方括号。无论大小如何都使用常量内存,使其非常适合 sum()、max()、any() 或馈送到其他迭代器。当不需要随机访问时,优先使用它们而非列表推导式。

python
# Like list comprehensions, but lazy (uses parentheses)
squares_list = [x ** 2 for x in range(10)]      # builds full list
squares_gen  = (x ** 2 for x in range(10))      # lazy generator

print(squares_gen)        # <generator object>
print(next(squares_gen))  # 0
print(next(squares_gen))  # 1

# Memory comparison
import sys
print(sys.getsizeof([x for x in range(10000)]))  # ~87616 bytes
print(sys.getsizeof((x for x in range(10000))))  # ~200 bytes (constant!)

# Use in sum(), list(), any() etc.
total = sum(x ** 2 for x in range(100))  # no extra list created
print(total)  # 328350

迭代器协议(__iter__、__next__)

迭代器协议要求 __iter__(返回迭代器)和 __next__(返回下一个值或抛出 StopIteration)。可迭代对象可以被循环遍历;迭代器一次产生一个值。对于可重用的可迭代对象,将可迭代对象(返回新迭代器)与迭代器(持有状态)分开。

python
class Range2:
    """A custom iterator that yields even numbers."""
    def __init__(self, start, end):
        self.current = start
        self.end = end

    def __iter__(self):
        return self  # the object is its own iterator

    def __next__(self):
        if self.current >= self.end:
            raise StopIteration
        value = self.current
        self.current += 2
        return value

r = Range2(0, 10)
for num in r:
    print(num)  # 0, 2, 4, 6, 8

# An iterable returns a fresh iterator each time __iter__ is called.
# An iterator returns itself and raises StopIteration when exhausted.

send()、throw()、close()

高级生成器方法支持双向通信:send() 将值传入生成器(成为 yield 的结果),throw() 在 yield 点注入异常,close() 终止生成器。在发送之前必须用 next() “启动”生成器。这些为协程和异步框架提供动力。

python
def echo():
    while True:
        received = yield  # yield without a value, receives via send()
        print(f"Echo: {received}")

gen = echo()
next(gen)          # prime the generator (advance to first yield)
gen.send("hello")  # Echo: hello
gen.send("world")  # Echo: world

# throw() injects an exception at the yield point
def safe_gen():
    try:
        while True:
            yield
    except ValueError:
        print("Caught ValueError inside generator")

g = safe_gen()
next(g)
g.throw(ValueError, "boom")  # Caught ValueError inside generator

# close() stops the generator (raises GeneratorExit)
gen.close()

生成器管道

生成器管道链接惰性生产者,使数据一次一项地流经各个阶段——每个项在读取下一个之前被完全处理。这避免了构建中间列表,是流数据处理的基础。Unix 管道在概念上以相同方式工作。

python
# Chain generators to build data-processing pipelines
def numbers():
    for i in range(1, 11):
        yield i

def squared(seq):
    for n in seq:
        yield n ** 2

def evens(seq):
    for n in seq:
        if n % 2 == 0:
            yield n

# Each stage processes one item at a time — no intermediate lists
pipeline = evens(squared(numbers()))
print(list(pipeline))  # [4, 16, 36, 64, 100]

# Equivalent with generator expressions:
result = (n for n in (x ** 2 for x in range(1, 11)) if n % 2 == 0)
print(list(result))  # [4, 16, 36, 64, 100]

yield from(委托)

yield from 将所有 yield(和 send/throw/close)委托给子迭代器,扁平化嵌套结构并组合协程。它对于递归生成器尤其强大——经典用例是扁平化任意嵌套的列表。在异步代码中,'await' 建立在相同概念上。

python
# yield from delegates to a sub-iterator (Python 3.3+)
def flatten(nested):
    for item in nested:
        if isinstance(item, (list, tuple)):
            yield from flatten(item)  # recursive delegation
        else:
            yield item

data = [1, [2, 3, [4, 5]], 6, [7, [8, [9]]]]
print(list(flatten(data)))
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

# yield from also forwards send()/throw() to the sub-generator,
# making it essential for coroutine composition.
17

上下文管理器

with 语句基础

with 语句确保即使发生异常也会释放资源(关闭文件、释放锁、归还连接)。它在开始时调用 __enter__,在结束时调用 __exit__。对于资源管理,始终优先使用 'with' 而非手动 try/finally——它更安全、更易读。

python
# 'with' guarantees cleanup even if an exception occurs
with open("data.txt", "r") as f:
    content = f.read()
# f.close() is called automatically here, even if read() raised

# Without 'with' you must manually close:
f = open("data.txt", "r")
try:
    content = f.read()
finally:
    f.close()  # easy to forget!

# Common built-in context managers:
with open("out.txt", "w") as f, open("in.txt") as g:
    f.write(g.read())  # both files close automatically

自定义上下文管理器(类)

基于类的上下文管理器实现 __enter__(设置,返回上下文对象)和 __exit__(exc_type, exc_val, exc_tb)(清理)。__exit__ 参数在发生异常时接收异常信息;返回 True 抑制异常。此模式非常适合数据库事务等复杂设置/拆卸。

python
class Timer:
    def __init__(self, label="Timer"):
        self.label = label

    def __enter__(self):
        import time
        self.start = time.perf_counter()
        return self  # value bound to 'as' variable

    def __exit__(self, exc_type, exc_val, exc_tb):
        import time
        elapsed = time.perf_counter() - self.start
        print(f"{self.label}: {elapsed:.4f}s")
        # Return False (or None) to propagate exceptions
        # Return True to suppress the exception
        return False

with Timer("Processing"):
    total = sum(i ** 2 for i in range(1_000_000))
# Processing: 0.1234s

contextlib.contextmanager

contextlib.contextmanager 将生成器函数转换为上下文管理器——yield 之前的代码是 __enter__,yield 之后(在 finally 中)的代码是 __exit__。对于简单情况,这比类更简洁。yield 一个值以提供给 'as' 变量。使用 try/finally 保证清理。

python
from contextlib import contextmanager
import time

@contextmanager
def timer(label="Timer"):
    start = time.perf_counter()
    try:
        yield  # code inside the 'with' block runs here
    finally:
        elapsed = time.perf_counter() - start
        print(f"{label}: {elapsed:.4f}s")

with timer("My task"):
    sum(i ** 2 for i in range(1_000_000))
# My task: 0.1234s

# You can also yield a value to bind with 'as'
@contextmanager
def open_db(path):
    db = connect(path)
    try:
        yield db
    finally:
        db.close()

with open_db("app.db") as db:
    db.query("SELECT 1")

多个上下文管理器

Python 3.10+ 允许带括号的多行 'with' 语句以获得更简洁的语法。对于动态数量的上下文管理器,contextlib.ExitStack 将它们作为一组管理并按相反顺序展开。当资源数量直到运行时才知道时,ExitStack 至关重要。

python
# Python 3.10+ supports parenthesized context managers
with (
    open("input.txt") as fin,
    open("output.txt", "w") as fout,
):
    fout.write(fin.read())

# Pre-3.10: nest them or use contextlib.ExitStack
from contextlib import ExitStack

files = ["a.txt", "b.txt", "c.txt"]
with ExitStack() as stack:
    handles = [stack.enter_context(open(f)) for f in files]
    for h in handles:
        print(h.read())

contextlib 工具(suppress、redirect)

contextlib.suppress 替换预期异常的 try/except/pass——可读性更强。redirect_stdout/redirect_stderr 捕获原本会输出到控制台的内容,对测试或日志记录有用。这些工具避免了样板代码并使意图明确。

python
from contextlib import suppress, redirect_stdout, redirect_stderr
import io, warnings

# suppress: ignore specific exceptions (cleaner than try/except/pass)
with suppress(FileNotFoundError):
    os.remove("temp.txt")  # no error if file doesn't exist

# redirect_stdout: capture print output
buffer = io.StringIO()
with redirect_stdout(buffer):
    print("This goes to the buffer, not console")
captured = buffer.getvalue()

# redirect_stderr: capture error/warning output
err_buf = io.StringIO()
with redirect_stderr(err_buf):
    warnings.warn("a warning")
print(err_buf.getvalue())  # the warning text

# Also: contextlib.chdir (3.11+) to temporarily change directory
# from contextlib import chdir
# with chdir("/tmp"): ...

异步上下文管理器

异步上下文管理器使用 __aenter__/__aexit__(注意 'a' 前缀)和 'async with' 语句。它们对于管理异步资源(如数据库连接或 HTTP 会话,例如 aiohttp.ClientSession)至关重要。即使块内发生 await 或异常,清理也会运行。

python
import asyncio

class AsyncDB:
    async def __aenter__(self):
        print("connecting...")
        await asyncio.sleep(0.1)  # simulate async connect
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        print("closing...")
        await asyncio.sleep(0.1)  # simulate async close
        return False

    async def query(self, sql):
        return f"result of: {sql}"

async def main():
    async with AsyncDB() as db:
        result = await db.query("SELECT 1")
        print(result)

asyncio.run(main())
# connecting...
# result of: SELECT 1
# closing...
18

类型提示

基本变量与函数注解

类型提示记录预期类型,但在运行时不强制执行——Python 仍然是动态类型的。使用 mypy 或 pyright 等静态检查器在运行前捕获类型错误。内置泛型(list[str]、dict[str, int])需要 Python 3.9+;旧版本需要 typing.List、typing.Dict。

python
# Variable annotations (Python 3.6+)
name: str = "Alice"
age: int = 30
scores: list[float] = [95.5, 88.0, 92.3]
config: dict[str, int] = {"timeout": 30}

# Function annotations
def greet(name: str, excited: bool = False) -> str:
    punctuation = "!" if excited else "."
    return f"Hello, {name}{punctuation}"

print(greet("World", excited=True))  # Hello, World!

# Annotations are optional and NOT enforced at runtime
def add(a: int, b: int) -> int:
    return a + b
add("2", "3")  # runs fine, returns "23" (no error!)

typing 模块(List、Dict、Tuple、Optional)

typing 模块为旧版 Python 提供泛型别名。从 3.9 起,可以直接使用内置类型(用 list[str] 代替 List[str])。Optional[X] 是 Union[X, None] 的简写——用它表示函数可能返回 None,迫使调用者处理 None 情况。

python
from typing import List, Dict, Tuple, Set, FrozenSet

# Pre-3.9 style (still works, needed for older Python)
names: List[str] = ["Alice", "Bob"]
scores: Dict[str, int] = {"Alice": 95}
point: Tuple[int, int] = (10, 20)
mixed: Tuple[str, int, float] = ("a", 1, 2.0)
variadic: Tuple[int, ...] = (1, 2, 3)  # variable-length

# Python 3.9+ built-in generics (preferred)
names: list[str] = ["Alice", "Bob"]
scores: dict[str, int] = {"Alice": 95}
point: tuple[int, int] = (10, 20)

# Optional means "could be None"
from typing import Optional
def find_user(uid: int) -> Optional[str]:
    if uid == 1:
        return "Alice"
    return None  # could also just 'return'

Union 与 Literal 类型

Union[X, Y](或 3.10+ 的 X | Y)表示值可以是任一类型。Literal 将值限制为特定常量——非常适合没有枚举开销的字符串枚举,以及重载函数分派。mypy 使用 Literal 在检查时收窄类型并捕获无效参数。

python
from typing import Union, Literal, overload

# Union: value can be one of several types
def process(data: Union[str, bytes]) -> str:
    if isinstance(data, bytes):
        return data.decode("utf-8")
    return data

# Python 3.10+ union syntax with | (preferred)
def process2(data: str | bytes) -> str:
    if isinstance(data, bytes):
        return data.decode("utf-8")
    return data

# Literal: restrict to specific constant values
def set_mode(mode: Literal["r", "w", "a"]) -> None:
    print(f"Mode set to {mode}")

set_mode("r")   # OK
# set_mode("x")  # mypy error: not a valid literal

# Literal for boolean-like flags
Direction = Literal["up", "down", "left", "right"]

TypeVar 与泛型

TypeVar 创建泛型类型变量,使函数和类可以保留类型关系(例如“返回与输入相同的类型”)。使用 bound= 约束到子类型,或指定约束如 TypeVar('T', int, float)。泛型类使用 Generic[T] 作为基类以成为参数化容器。

python
from typing import TypeVar, Generic, List

T = TypeVar("T")  # a generic type variable

def first(items: List[T]) -> T:
    return items[0]

# Type inference: T is bound to the argument's type
x: int = first([1, 2, 3])        # T = int
y: str = first(["a", "b", "c"])  # T = str

# Bounded TypeVar: T must be a subtype of Number
from typing import TypeVar
from numbers import Number
N = TypeVar("N", bound=Number)

def sum_all(values: list[N]) -> N:
    total = values[0]
    for v in values[1:]:
        total = total + v
    return total

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

s: Stack[int] = Stack()
s.push(1)
# s.push("x")  # mypy error

Callable、类型别名与 Protocol

Callable[[int, str], bool] 描述接受 int 和 str、返回 bool 的函数。类型别名为复杂类型提供描述性名称。Protocol 启用结构化(鸭子)类型——任何具有正确方法的对象都满足协议,无需继承。这是 Python 对接口的回答。

python
from typing import Callable, Protocol, TypeAlias

# Callable signature: Callable[[ArgTypes], ReturnType]
def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
    return func(a, b)

apply(lambda x, y: x + y, 3, 4)  # 7

# Type aliases (3.12+ uses 'type' statement; older uses assignment)
type Vector = list[float]          # 3.12+
Vector2: TypeAlias = list[float]   # 3.10+

def magnitude(v: Vector) -> float:
    return sum(x ** 2 for x in v) ** 0.5

# Protocol: structural typing (duck typing with static checks)
class Drawable(Protocol):
    def draw(self) -> None: ...

def render(obj: Drawable) -> None:
    obj.draw()  # any object with a draw() method works

class Circle:
    def draw(self) -> None:
        print("drawing circle")

render(Circle())  # OK — Circle has draw()

使用 mypy 进行类型检查

mypy 是 Python 最流行的静态类型检查器——它分析类型提示而无需运行代码。它捕获 None 处理 bug、错误参数类型和缺失的返回。从渐进式类型化开始:向新代码添加提示并在 CI 中运行 mypy。新项目使用 --strict 以强制执行全面注解。

python
# Save as example.py, then run:  mypy example.py
from typing import Optional

def divide(a: float, b: float) -> Optional[float]:
    if b == 0:
        return None
    return a / b

result = divide(10, 0)
# Without checking, this would crash at runtime:
# print(result + 1)  # TypeError: NoneType + int

# mypy catches it:
# error: Unsupported operand types for + ("None" and "int")
# fix: check for None first
if result is not None:
    print(result + 1)

# Run strict mode for maximum safety:
#   mypy --strict example.py
# Common strict flags: --disallow-untyped-defs, --no-implicit-optional
19

数据类

基础 @dataclass

@dataclass 根据注解字段自动生成 __init__、__repr__ 和 __eq__——消除了数据持有类的样板代码。它非常适合值对象、配置、DTO 和记录。从 Python 3.7 起可用。字段必须有类型注解;注解定义字段。

python
from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float

p1 = Point(1.0, 2.0)
p2 = Point(1.0, 2.0)

print(p1)         # Point(x=1.0, y=2.0)  — auto __repr__
print(p1 == p2)   # True  — auto __eq__ (compares fields)
print(p1.x)       # 1.0

# Without @dataclass you'd write all this boilerplate:
# class Point:
#     def __init__(self, x, y): self.x = x; self.y = y
#     def __repr__(self): ...
#     def __eq__(self, other): ...

默认值与 default_factory

可变默认值(列表、字典、集合)必须使用 field(default_factory=list)——直接使用 [] 会在所有实例间共享一个列表,这是一个经典 bug。default_factory 每个实例调用一次以创建新对象。简单的不可变默认值(int、str、bool、None)可以直接赋值。

python
from dataclasses import dataclass, field

@dataclass
class Student:
    name: str
    grade: str = "A"          # simple default
    tags: list[str] = field(default_factory=list)  # mutable default!
    scores: dict[str, int] = field(default_factory=dict)

s = Student("Alice")
print(s)  # Student(name='Alice', grade='A', tags=[], scores={})

s.tags.append("honors")
s2 = Student("Bob")
print(s2.tags)  # [] — each instance gets its own list

# NEVER use [] or {} as a direct default — all instances would share
# the same mutable object (classic Python pitfall).

frozen、eq 与 order

frozen=True 使数据类不可变——字段不能重新赋值,实例变为可哈希(可用作字典键或集合成员)。order=True 添加比较方法用于排序。将 frozen=True 与 order=True 结合用于不可变、可排序的值类型,如坐标、颜色或版本。

python
from dataclasses import dataclass

# frozen=True makes instances immutable (hashable, usable as dict keys)
@dataclass(frozen=True)
class Color:
    r: int
    g: int
    b: int

c = Color(255, 0, 0)
# c.r = 128  # FrozenInstanceError!
print(hash(c))  # works — frozen dataclasses are hashable

# order=True generates __lt__, __le__, __gt__, __ge__ for sorting
@dataclass(order=True)
class Priority:
    level: int

tasks = [Priority(3), Priority(1), Priority(2)]
tasks.sort()
print(tasks)  # [Priority(level=1), Priority(level=2), Priority(level=3)]

# Common combo: frozen + order for immutable comparable values
@dataclass(frozen=True, order=True)
class Version:
    major: int
    minor: int

__post_init__ 与字段自定义

__post_init__ 在生成的 __init__ 之后自动运行——用它计算派生字段、验证值或执行设置。field(init=False) 创建不在构造函数中的字段(适用于计算/缓存值)。field(repr=False, compare=False) 从 repr 和相等性检查中隐藏字段。

python
from dataclasses import dataclass, field

@dataclass
class User:
    email: str
    _email_normalized: str = field(init=False, repr=False)
    id: int = field(default=0)

    def __post_init__(self):
        # runs after __init__; compute derived fields here
        self._email_normalized = self.email.strip().lower()

u = User("  [email protected] ")
print(u.email)             # '  [email protected] '
print(u._email_normalized) # '[email protected]'

# field(init=False) excludes a field from __init__
# field(repr=False) hides it from the repr
# field(compare=False) excludes from __eq__/__hash__
# field(metadata={...}) attaches custom metadata

继承与 slots

数据类支持继承——子字段附加在父字段之后,可以覆盖父默认值。注意:父类中有默认值的字段后面不能跟子类中无默认值的字段。slots=True(3.10+)防止添加任意属性并显著减少每个实例的内存——非常适合数百万个小对象。

python
from dataclasses import dataclass

@dataclass
class Animal:
    name: str
    sound: str = "..."

@dataclass
class Dog(Animal):
    breed: str = "unknown"
    sound: str = "Woof"  # override parent default

d = Dog("Rex", breed="Labrador")
print(d)  # Dog(name='Rex', sound='Woof', breed='Labrador')

# Python 3.10+: slots=True saves memory (no __dict__)
@dataclass(slots=True)
class Pixel:
    r: int
    g: int
    b: int

p = Pixel(0, 128, 255)
# p.new_field = 1  # AttributeError — slots prevent arbitrary attrs
# Saves ~40-50% memory vs regular dataclass for many instances
20

Collections 与 Itertools

namedtuple

namedtuple 创建具有命名字段的元组子类——与元组一样内存高效,但可读性更强。它们是不可变的,所以用 _replace() 创建修改后的副本。新代码优先使用 typing.NamedTuple,因为它支持类型注解和默认值。非常适合从函数返回多个值。

python
from collections import namedtuple

# Lightweight immutable class with named fields
Point = namedtuple("Point", ["x", "y"])
p = Point(3, 4)
print(p.x, p.y)       # 3 4  — access by name
print(p[0], p[1])     # 3 4  — also by index
print(p._asdict())    # {'x': 3, 'y': 4}

# More memory-efficient than a full class
# Use _replace to create a modified copy (immutable!)
p2 = p._replace(x=10)
print(p2)  # Point(x=10, y=4)

# Python 3.6+ typing.NamedTuple for type hints:
from typing import NamedTuple
class Point3D(NamedTuple):
    x: float
    y: float
    z: float = 0.0

Counter

Counter 是用于计数可哈希对象的 dict 子类——非常适合频率分析、直方图和投票。most_common(n) 返回前 n 项。缺失的键返回 0 而不是抛出 KeyError。Counter 支持 +、-、&、| 用于计数的集合式运算。

python
from collections import Counter

# Count hashable items
words = "the cat sat on the mat the cat".split()
c = Counter(words)
print(c)  # Counter({'the': 3, 'cat': 2, 'sat': 1, 'on': 1, 'mat': 1})

# Most common elements
print(c.most_common(2))  # [('the', 3), ('cat', 2)]

# Arithmetic on counters
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
print(c1 + c2)  # Counter({'a': 4, 'b': 3})
print(c1 - c2)  # Counter({'a': 2})  (drops zero/negatives)

# Missing keys return 0 (not KeyError)
print(c["dog"])  # 0

# Update and elements
c.update(["cat", "cat"])
print(sorted(c.elements()))  # ['cat','cat','cat','cat','mat','on','sat','the','the','the']

defaultdict

defaultdict 使用工厂函数的默认值自动创建缺失的键——list 用于分组,int 用于计数,set 用于去重。这消除了 'if key not in dict' 样板。工厂仅在键缺失时调用,而非每次访问。

python
from collections import defaultdict

# Group items by key without checking if key exists
words = ["apple", "banana", "avocado", "blueberry", "cherry"]
by_first = defaultdict(list)
for w in words:
    by_first[w[0]].append(w)
print(dict(by_first))
# {'a': ['apple', 'avocado'], 'b': ['banana', 'blueberry'], 'c': ['cherry']}

# Counting with int (default 0)
counts = defaultdict(int)
for w in words:
    counts[w[0]] += 1
print(dict(counts))  # {'a': 2, 'b': 2, 'c': 1}

# Nested defaultdicts
tree = defaultdict(lambda: defaultdict(list))
tree["2024"]["Jan"].append("event1")

# vs regular dict: avoids the key-check boilerplate
# d = {}
# for w in words:
#     if w[0] not in d:
#         d[w[0]] = []
#     d[w[0]].append(w)

OrderedDict 与 deque

deque 在两端提供 O(1) 的追加/弹出——将其用于队列、BFS 和滑动窗口而非列表(list.pop(0) 是 O(n))。使用 maxlen 时,deque 自动丢弃旧项,非常适合有界缓冲区。自 3.7 起 OrderedDict 不那么需要(字典有序),但其 move_to_end 和 popitem 对 LRU 缓存仍然独特有用。

python
from collections import OrderedDict, deque

# deque: double-ended queue, O(1) append/pop at both ends
dq = deque([1, 2, 3], maxlen=5)
dq.appendleft(0)   # deque([0, 1, 2, 3])
dq.append(4)       # deque([0, 1, 2, 3, 4])
dq.append(5)       # deque([1, 2, 3, 4, 5]) — oldest dropped (maxlen!)
print(dq.popleft())  # 1
print(dq)            # deque([2, 3, 4, 5])

# deque is ideal for queues, BFS, sliding windows
from collections import deque
queue = deque(["task1", "task2"])
queue.append("task3")
next_task = queue.popleft()  # FIFO — O(1) vs list.pop(0) which is O(n)

# OrderedDict: remembers insertion order (regular dicts do too in 3.7+,
# but OrderedDict has move_to_end and equality is order-sensitive)
od = OrderedDict([("a", 1), ("b", 2)])
od.move_to_end("a")  # move to last
print(list(od))  # ['b', 'a']
od.popitem(last=False)  # pop first item (FIFO)

itertools:chain、product、combinations、permutations

itertools 提供快速、内存高效的组合学工具。chain 惰性扁平化可迭代对象。product 给出笛卡尔积(替代嵌套 for 循环)。combinations/permutations 生成选择而不构建完整列表——对大型或无限输入至关重要。全部返回迭代器,所以用 list() 包装以查看。

python
from itertools import chain, product, combinations, permutations

# chain: flatten multiple iterables
list(chain([1, 2], [3, 4], [5]))  # [1, 2, 3, 4, 5]
list(chain.from_iterable([[1, 2], [3, 4]]))  # [1, 2, 3, 4]

# product: Cartesian product (nested loops)
list(product([1, 2], ["a", "b"]))
# [(1,'a'), (1,'b'), (2,'a'), (2,'b')]
list(product("AB", repeat=2))  # [('A','A'),('A','B'),('B','A'),('B','B')]

# combinations: unordered selections (no repeats)
list(combinations("ABC", 2))  # [('A','B'),('A','C'),('B','C')]
list(combinations("AAA", 2))  # [('A','A'),('A','A'),('A','A')]

# permutations: ordered arrangements
list(permutations("ABC", 2))  # [('A','B'),('A','C'),('B','A'),('B','C'),('C','A'),('C','B')]

# combinations_with_replacement: allow picking same element
from itertools import combinations_with_replacement
list(combinations_with_replacement("AB", 2))  # [('A','A'),('A','B'),('B','B')]

itertools:groupby、accumulate、starmap

groupby 分组共享键的连续元素——先按键排序,否则同一键会得到多个组。accumulate 产生运行总计/乘积。islice、takewhile 和 dropwhile 是切片和过滤的惰性替代方案,适用于任何迭代器,包括无限迭代器。

python
from itertools import groupby, accumulate, starmap, islice, takewhile, dropwhile

# groupby: group consecutive items by a key (sort first!)
data = [("A", 1), ("A", 2), ("B", 3), ("B", 4), ("A", 5)]
data.sort(key=lambda x: x[0])  # MUST sort by key first
for key, group in groupby(data, key=lambda x: x[0]):
    print(key, list(group))
# A [('A',1),('A',2),('A',5)]
# B [('B',3),('B',4)]

# accumulate: running aggregate (sum by default)
list(accumulate([1, 2, 3, 4]))  # [1, 3, 6, 10]
import operator
list(accumulate([1, 2, 3, 4], operator.mul))  # [1, 2, 6, 24]

# starmap: unpack args from tuples before calling
list(starmap(pow, [(2, 3), (3, 2), (10, 3)]))  # [8, 9, 1000]

# islice: slice an iterator (doesn't support negative indices)
list(islice(range(100), 5, 10))  # [5, 6, 7, 8, 9]

# takewhile / dropwhile: filter by predicate
list(takewhile(lambda x: x < 5, [1, 4, 6, 3, 8]))  # [1, 4]
list(dropwhile(lambda x: x < 5, [1, 4, 6, 3, 8]))  # [6, 3, 8]

functools:lru_cache、partial、reduce

lru_cache 记忆结果——为递归或昂贵的纯函数带来显著加速;cache_info() 显示命中/未命中统计。partial 预填充参数以创建专用可调用对象。reduce 累积应用函数(尽管 sum()、any()、all() 经常替代它)。cached_property 计算一次然后缓存在实例上。

python
from functools import lru_cache, partial, reduce
import operator

# lru_cache: memoize function results (Least Recently Used)
@lru_cache(maxsize=128)
def fib(n):
    if n < 2:
        return n
    return fib(n - 1) + fib(n - 2)

print(fib(100))  # instant (without cache: impossibly slow)
print(fib.cache_info())  # CacheInfo(hits=98, misses=101, ...)

# partial: fix some arguments, create a new callable
def power(base, exponent):
    return base ** exponent

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

# reduce: cumulatively apply a function, reducing to one value
product = reduce(operator.mul, [1, 2, 3, 4])  # 24
# Equivalent: ((1*2)*3)*4

# Python 3.8+: cached_property for lazy computed attributes
from functools import cached_property
class Data:
    @cached_property
    def expensive(self):
        print("computing...")
        return [i ** 2 for i in range(1000000)]
21

JSON 与 CSV 处理

json.dumps 与 json.loads

json.dumps()(dump string)将 Python 对象序列化为 JSON 字符串;json.loads()(load string)将 JSON 解析回来。使用 indent 提高可读性,ensure_ascii=False 保持 Unicode 字符可读,sort_keys 用于确定性输出。JSON 键必须是字符串——int 键变为字符串。

python
import json

# Serialize Python object to JSON string
data = {"name": "Alice", "age": 30, "scores": [95, 88, 92]}
json_str = json.dumps(data)
print(json_str)  # {"name": "Alice", "age": 30, "scores": [95, 88, 92]}

# Pretty-print with indent
print(json.dumps(data, indent=2))
# {
#   "name": "Alice",
#   "age": 30,
#   "scores": [95, 88, 92]
# }

# Parse JSON string to Python object
parsed = json.loads(json_str)
print(parsed["name"])  # Alice
print(type(parsed["scores"]))  # <class 'list'>

# Sort keys, handle non-ASCII
print(json.dumps({"name": "Zoë"}, ensure_ascii=False, sort_keys=True))

读写 JSON 文件

json.dump() 直接写入文件对象;json.load() 从文件对象读取。始终指定 encoding='utf-8' 以保证可移植性。记住类型映射:JSON 对象变为 dict,数组变为 list,数字变为 int 或 float。Datetime、set 和自定义对象默认不可 JSON 序列化。

python
import json

data = {"users": [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]}

# Write to file
with open("data.json", "w", encoding="utf-8") as f:
    json.dump(data, f, indent=2, ensure_ascii=False)

# Read from file
with open("data.json", "r", encoding="utf-8") as f:
    loaded = json.load(f)

print(loaded["users"][0]["name"])  # Alice

# Type conversions to remember:
# JSON object  <-> Python dict
# JSON array   <-> Python list
# JSON string  <-> Python str
# JSON number  <-> Python int/float
# JSON true/false <-> Python True/False
# JSON null    <-> Python None

自定义 JSON 编码(datetime、自定义对象)

json 模块默认无法序列化 datetime、set 或自定义类。提供 default 函数(为不可序列化对象调用)或 JSONEncoder 子类。对于往返转换,将自定义编码器与 loads() 中的 object_hook 配对以重建原始类型。这是 ORM 和 ORM 序列化模型对象的方式。

python
import json
from datetime import datetime

# Default behavior: TypeError on non-serializable types
# json.dumps({"now": datetime.now()})  # TypeError!

# Solution 1: default function for unknown types
def default_encoder(obj):
    if isinstance(obj, datetime):
        return obj.isoformat()
    if isinstance(obj, set):
        return sorted(obj)
    raise TypeError(f"Cannot serialize {type(obj)}")

data = {"now": datetime.now(), "tags": {"a", "b"}}
print(json.dumps(data, default=default_encoder))

# Solution 2: custom JSONEncoder subclass
class MyEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return {"__datetime__": obj.isoformat()}
        return super().default(obj)

print(json.dumps(data, cls=MyEncoder))

# Decoding with object_hook
def decoder(dct):
    if "__datetime__" in dct:
        return datetime.fromisoformat(dct["__datetime__"])
    return dct
json.loads(json.dumps(data, cls=MyEncoder), object_hook=decoder)

读取 CSV 文件

始终用 newline='' 打开 CSV 文件以避免 Windows 上的空行问题。csv.reader 返回列表;csv.DictReader 返回以标题行为键的字典。csv 模块正确处理引用、嵌入逗号和换行符——永远不要用 line.split(',') 手动分割 CSV 行。使用 Sniffer 自动检测分隔符。

python
import csv

# Basic reader: each row is a list of strings
with open("data.csv", newline="", encoding="utf-8") as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)  # ['name', 'age', 'city']

# DictReader: each row is a dict keyed by header
with open("data.csv", newline="") as f:
    reader = csv.DictReader(f)
    for row in reader:
        print(row["name"], row["age"])  # access by column name

# Handle different delimiters and quoting
with open("data.tsv", newline="") as f:
    reader = csv.reader(f, delimiter="\t", quotechar='"')
    for row in reader:
        print(row)

# Sniffer to auto-detect format
with open("unknown.csv", newline="") as f:
    sample = f.read(1024)
    dialect = csv.Sniffer().sniff(sample)
    f.seek(0)
    reader = csv.reader(f, dialect)

写入 CSV 文件

csv.writer 写入列表;csv.DictWriter 用固定的字段名集合写入字典。打开文件时始终使用 newline=''。quoting 参数控制何时引用字段——QUOTE_MINIMAL(默认)仅在需要时引用,QUOTE_ALL 引用所有内容,对严格解析器有用。

python
import csv

rows = [
    ["name", "age", "city"],
    ["Alice", 30, "NYC"],
    ["Bob", 25, "LA"],
]

# Basic writer
with open("out.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerows(rows)  # write multiple rows

# DictWriter: write from dicts
with open("out.csv", "w", newline="") as f:
    fieldnames = ["name", "age", "city"]
    writer = csv.DictWriter(f, fieldnames=fieldnames)
    writer.writeheader()
    writer.writerow({"name": "Alice", "age": 30, "city": "NYC"})
    writer.writerow({"name": "Bob", "age": 25, "city": "LA"})

# Control quoting: QUOTE_MINIMAL (default), QUOTE_ALL, QUOTE_NONNUMERIC
writer = csv.writer(f, quoting=csv.QUOTE_ALL)
# QUOTE_ALL wraps every field in quotes: "Alice","30","NYC"

JSON Lines(NDJSON)与流式处理

JSON Lines(NDJSON)每行放一个 JSON 对象——非常适合日志、事件流和仅追加文件,因为可以独立处理每一行。对于巨大的单个 JSON 文档,使用 ijson 库进行流式解析而无需将整个文件加载到内存。NDJSON 是许多数据管道的标准。

python
import json

# JSON Lines: one JSON object per line (great for logs, big data)
records = [{"id": 1, "msg": "first"}, {"id": 2, "msg": "second"}]

# Write NDJSON
with open("logs.jsonl", "w") as f:
    for rec in records:
        f.write(json.dumps(rec) + "\n")

# Read NDJSON line by line (memory-efficient for huge files)
with open("logs.jsonl", "r") as f:
    for line in f:
        rec = json.loads(line)
        print(rec["id"], rec["msg"])

# Stream large JSON arrays without loading everything into memory
# Use ijson library for streaming parsing of huge JSON files:
# import ijson
# with open("huge.json", "rb") as f:
#     for item in ijson.items(f, "items.item"):
#         process(item)  # one item at a time
22

日志与测试

logging 基础

logging 模块是发出诊断输出的标准方式——远胜于 print(),因为你可以控制级别、格式和目标。每个模块使用 logging.getLogger(__name__) 以便可以按模块调整详细程度。logging.exception() 自动包含回溯。在启动时配置一次 basicConfig。

python
import logging

# Basic configuration (call once at program start)
logging.basicConfig(
    level=logging.DEBUG,
    format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)

# Log levels (severity ascending)
logging.debug("Detailed debug info")     # DEBUG (10)
logging.info("General information")       # INFO (20)
logging.warning("Something unexpected")   # WARNING (30)
logging.error("A real error occurred")    # ERROR (40)
logging.critical("System is down")        # CRITICAL (50)

# Logging exceptions with traceback
try:
    1 / 0
except ZeroDivisionError:
    logging.exception("Division failed")  # includes full traceback

# Get a named logger (best practice per module)
logger = logging.getLogger(__name__)
logger.info("Module-specific log")

记录到文件与多个处理器

处理器将日志记录路由到目标——控制台、文件、网络、电子邮件。RotatingFileHandler 限制文件大小并保留备份,防止日志无限增长。每个处理器可以有自己的级别和格式(例如,详细日志到文件,简洁日志到控制台)。TimedRotatingFileHandler 按时间而非大小轮转。

python
import logging
from logging.handlers import RotatingFileHandler

logger = logging.getLogger("myapp")
logger.setLevel(logging.DEBUG)

# Console handler (INFO and above)
console = logging.StreamHandler()
console.setLevel(logging.INFO)
console.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))

# Rotating file handler (DEBUG and above, max 5MB x 3 backups)
file_handler = RotatingFileHandler(
    "app.log", maxBytes=5_000_000, backupCount=3, encoding="utf-8"
)
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(
    logging.Formatter("%(asctime)s [%(levelname)s] %(name)s: %(message)s")
)

logger.addHandler(console)
logger.addHandler(file_handler)

logger.debug("debug to file only")
logger.info("info to both console and file")
logger.error("error everywhere")

unittest 基础

unittest 是 Python 的内置测试框架(xUnit 风格)。测试位于继承 TestCase 的类中。setUp/tearDown 在每个测试前后运行以实现隔离。常用断言:assertEqual、assertTrue、assertRaises、assertIn。用 python -m unittest 运行以自动发现 test_*.py 文件。

python
import unittest

def add(a, b):
    return a + b

def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

class TestMath(unittest.TestCase):
    def setUp(self):
        # runs before each test method
        self.data = [1, 2, 3]

    def tearDown(self):
        # runs after each test method
        pass

    def test_add(self):
        self.assertEqual(add(1, 2), 3)
        self.assertEqual(add(-1, 1), 0)

    def test_add_types(self):
        self.assertEqual(add("a", "b"), "ab")

    def test_divide_by_zero(self):
        with self.assertRaises(ValueError):
            divide(1, 0)

    def test_membership(self):
        self.assertIn(2, self.data)
        self.assertTrue(3 in self.data)

if __name__ == "__main__":
    unittest.main()
# Run: python -m unittest test_file.py -v

pytest 基础

pytest 是最受欢迎的 Python 测试工具——简单的 assert 语句给出丰富的失败报告,无需样板类。pytest.raises 检查异常并支持可选的正则匹配。pytest.approx 处理浮点比较不精确。用 pip install pytest 安装,用 pytest -v 运行以获得详细输出。

python
# test_math.py — pytest is simpler and more powerful than unittest
# Install: pip install pytest
# Run: pytest -v

def add(a, b):
    return a + b

def divide(a, b):
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b

# Plain functions, no classes required
def test_add():
    assert add(1, 2) == 3
    assert add(-1, 1) == 0

def test_add_strings():
    assert add("hello", " world") == "hello world"

# Testing exceptions with pytest.raises
import pytest

def test_divide_by_zero():
    with pytest.raises(ValueError, match="Cannot divide by zero"):
        divide(1, 0)

# Approximate float comparison
def test_float():
    assert 0.1 + 0.2 == pytest.approx(0.3)

pytest Fixtures

Fixtures 是 pytest 的依赖注入——它们通过参数名向测试提供设置数据、模拟对象或资源。基于 yield 的 fixture 处理设置(yield 之前)和拆卸(yield 之后)。作用域控制重用:'session' 为整个运行创建一次 fixture,'module' 每个文件一次,'function'(默认)每个测试一次。

python
import pytest

# A fixture provides setup data/resources to tests
@pytest.fixture
def sample_list():
    return [1, 2, 3, 4, 5]

# Use fixtures by passing their name as a parameter
def test_length(sample_list):
    assert len(sample_list) == 5

def test_sum(sample_list):
    assert sum(sample_list) == 15

# Fixture with setup AND teardown (yield)
@pytest.fixture
def db_connection():
    print("\n[setup] connecting to DB")
    conn = {"connected": True}
    yield conn  # test runs here; value passed to test
    print("\n[teardown] closing DB")
    conn["connected"] = False

def test_db(db_connection):
    assert db_connection["connected"] is True

# Fixture scopes: function (default), class, module, session
@pytest.fixture(scope="session")
def expensive_resource():
    return load_large_dataset()  # created once per test session

pytest parametrize 与 mocking

parametrize 在多个输入集上运行单个测试函数——消除复制粘贴测试代码并给出清晰的每用例输出。unittest.mock.patch 用 mock 替换函数/对象以进行隔离测试。assert_called_once_with 验证 mock 是否被正确使用。@pytest.mark.skip 和 xfail 优雅地处理不完整的测试。

python
import pytest
from unittest.mock import patch, MagicMock

# parametrize: run one test with multiple inputs
@pytest.mark.parametrize("a, b, expected", [
    (1, 2, 3),
    (-1, 1, 0),
    (0, 0, 0),
    (100, 200, 300),
])
def test_add_many(a, b, expected):
    assert add(a, b) == expected

# parametrize with IDs for readable output
@pytest.mark.parametrize("x", [1, 2, 3], ids=["one", "two", "three"])
def test_ids(x):
    assert x > 0

# Mocking: replace external dependencies
def fetch_user(uid):
    # imagine this calls a real API
    return {"id": uid, "name": "real_user"}

@patch("__main__.fetch_user")
def test_with_mock(mock_fetch):
    mock_fetch.return_value = {"id": 1, "name": "mocked"}
    result = fetch_user(1)
    assert result["name"] == "mocked"
    mock_fetch.assert_called_once_with(1)

# Skip and expected failure
@pytest.mark.skip(reason="not implemented yet")
def test_future():
    pass

@pytest.mark.xfail(reason="known bug #42")
def test_known_bug():
    assert 1 == 2
23

网络编程

TCP 服务器

使用 socket 模块创建 TCP 服务器。bind 将套接字与地址关联,listen 设置积压队列,accept 阻塞直到客户端连接。始终关闭连接以释放文件描述符。

python
import socket
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('localhost', 8080))
server.listen(5)
conn, addr = server.accept()
data = conn.recv(1024)
conn.sendall(b'Hello')
conn.close()

TCP 客户端

创建连接到服务器的 TCP 客户端。connect 建立连接,sendall 发送所有字节,recv 读取最多指定字节数。使用 encode/decode 进行字符串与字节转换。

python
import socket
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(('localhost', 8080))
client.sendall(b'Hello Server')
response = client.recv(1024)
print(response.decode())
client.close()

UDP 套接字

UDP 是无连接的:无握手,无保证交付。recvfrom 返回数据和发送方地址。UDP 使用 SOCK_DGRAM。适用于 DNS、游戏和实时流。

python
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('localhost', 9090))
data, addr = sock.recvfrom(1024)
print(f"From {addr}: {data.decode()}")
sock.sendto(b'Reply', addr)

HTTP 服务器

http.server 模块提供简单的 HTTP 服务器。继承 BaseHTTPRequestHandler 并重写 do_GET、do_POST。仅用于开发;生产使用 gunicorn。

python
from http.server import HTTPServer, BaseHTTPRequestHandler
class Handler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-Type', 'text/html')
        self.end_headers()
        self.wfile.write(b'<h1>Hello</h1>')
HTTPServer(('localhost', 8000), Handler).serve_forever()

套接字超时

settimeout 为所有套接字操作设置超时。如果操作超过超时,抛出 socket.timeout 异常。使用 try/finally 确保清理。

python
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5.0)
try:
    sock.connect(('example.com', 80))
    data = sock.recv(1024)
except socket.timeout:
    print('Connection timed out')
finally:
    sock.close()
24

数据库(SQLite)

创建表

sqlite3 内置于 Python。connect 创建或打开数据库文件。CREATE TABLE IF NOT EXISTS 防止表已存在时出错。始终调用 commit 保存更改。

python
import sqlite3
conn = sqlite3.connect('example.db')
cursor = conn.cursor()
cursor.execute('''CREATE TABLE IF NOT EXISTS users (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL, email TEXT UNIQUE, age INTEGER)''')
conn.commit()

插入数据

始终使用参数化查询(? 占位符)以防止 SQL 注入。lastrowid 返回自增 ID。永远不要对 SQL 值使用字符串格式化。

python
cursor.execute(
    'INSERT INTO users (name, email, age) VALUES (?, ?, ?)',
    ('Alice', '[email protected]', 30))
conn.commit()
print(f"ID: {cursor.lastrowid}")

查询数据

fetchall 以元组列表形式返回所有匹配行。fetchone 返回单行或 None。对于大型结果集,直接迭代游标。

python
cursor.execute('SELECT * FROM users WHERE age > ?', (25,))
rows = cursor.fetchall()
for row in rows:
    print(row)
cursor.execute('SELECT * FROM users WHERE id = ?', (1,))
user = cursor.fetchone()

更新与删除

UPDATE 修改现有行,DELETE 删除它们。rowcount 指示受影响行数。DELETE 始终使用 WHERE。commit 持久化更改。

python
cursor.execute('UPDATE users SET age = ? WHERE name = ?', (31, 'Alice'))
cursor.execute('DELETE FROM users WHERE age < ?', (18,))
conn.commit()
print(f"Affected: {cursor.rowcount} rows")

行工厂

使用 conn 作为上下文管理器在成功时自动提交,在异常时回滚。row_factory = sqlite3.Row 允许按名称访问列。

python
conn = sqlite3.connect('example.db')
conn.row_factory = sqlite3.Row
with conn:
    conn.execute('INSERT INTO users (name, email) VALUES (?, ?)',
                 ('Bob', '[email protected]'))
for row in conn.execute('SELECT * FROM users'):
    print(row['name'], row['email'])
25

网页抓取

BeautifulSoup 基础

requests 获取 HTML 内容,BeautifulSoup 解析它。html.parser 是内置的;lxml 更快。解析前始终检查 response.status_code。

python
import requests
from bs4 import BeautifulSoup
resp = requests.get('https://example.com')
soup = BeautifulSoup(resp.text, 'html.parser')
print(soup.title.string)
print(soup.find('h1').text)

查找元素

find_all 返回所有匹配元素,find 返回第一个。使用 class_(带下划线)。select 使用 CSS 选择器进行复杂查询。

python
links = soup.find_all('a')
for link in links:
    print(link.get('href'), link.text)
article = soup.find('div', class_='article')
items = soup.select('ul.list > li.item')

提取表格

表格结构为 tr(行)包含 td(数据)或 th(标题)单元格。strip 去除空白。find_all 接受标签名列表。

python
table = soup.find('table')
for row in table.find_all('tr'):
    cols = row.find_all(['td', 'th'])
    data = [col.text.strip() for col in cols]
    print(data)

处理分页

通过跟随下一页链接处理分页。select_one 返回第一个匹配或 None。在请求之间添加 time.sleep。

python
all_items = []
url = 'https://example.com/page/1'
while url:
    resp = requests.get(url)
    soup = BeautifulSoup(resp.text, 'html.parser')
    all_items.extend([i.text for i in soup.select('.item')])
    next_link = soup.select_one('a.next')
    url = next_link.get('href') if next_link else None

保存为 CSV

csv.DictWriter 将字典写入 CSV。newline 防止 Windows 上出现额外空行。encoding=utf-8 处理特殊字符。

python
import csv
with open('data.csv', 'w', newline='', encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames=['name', 'price'])
    writer.writeheader()
    for item in scraped_data:
        writer.writerow(item)
26

异步 Web(aiohttp)

HTTP 客户端

aiohttp 提供异步 HTTP。ClientSession 管理连接池。async with 确保清理。asyncio.run 执行协程。

python
import aiohttp, asyncio
async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as resp:
            return await resp.text()
data = asyncio.run(fetch('https://api.example.com'))

并发请求

asyncio.gather 并发运行协程,减少总时间。所有请求共享同一会话。使用信号量限制并发。

python
async def fetch_all(urls):
    async with aiohttp.ClientSession() as session:
        tasks = [session.get(url) for url in urls]
        responses = await asyncio.gather(*tasks)
        return [await r.text() for r in responses]

Web 服务器

aiohttp.web 创建异步 Web 服务器。路由用 HTTP 方法和路径模式定义。match_info 提取路径参数。

python
from aiohttp import web
async def handle(request):
    name = request.match_info.get('name', 'World')
    return web.json_response({'message': f'Hello, {name}!'})
app = web.Application()
app.add_routes([web.get('/', handle), web.get('/{name}', handle)])
web.run_app(app, port=8080)

WebSocket 服务器

WebSocket 启用双向实时通信。WebSocketResponse 处理升级握手。async for 迭代消息。

python
async def ws_handler(request):
    ws = web.WebSocketResponse()
    await ws.prepare(request)
    async for msg in ws:
        if msg.type == aiohttp.WSMsgType.TEXT:
            await ws.send_str(f'Echo: {msg.data}')
    return ws

带 Cookie 的会话

ClientSession 自动在请求间持久化 cookie。对于认证抓取至关重要。所有请求使用单一会话。

python
async def login_and_fetch():
    async with aiohttp.ClientSession() as session:
        await session.post('https://example.com/login',
                          data={'user': 'admin', 'pass': '123'})
        resp = await session.get('https://example.com/dashboard')
        return await resp.text()
27

多进程深入

进程池

Pool 管理工作进程。map 并行分配工作。apply_async 异步运行单个函数。在 Windows 上始终使用 if __name__ == main 保护。

python
from multiprocessing import Pool
def square(x): return x * x
if __name__ == '__main__':
    with Pool(4) as pool:
        results = pool.map(square, range(10))
        result = pool.apply_async(square, (100,))
        print(result.get(timeout=5))

共享内存

Value 和 Array 在进程间创建共享内存。使用 get_lock 同步访问并防止竞态条件。

python
from multiprocessing import Value, Array
counter = Value('i', 0)
arr = Array('d', [0.0, 1.0, 2.0])
with counter.get_lock():
    counter.value += 1

队列通信

Queue 实现进程间安全通信。put 添加项,get 检索项。Queue 是进程安全的,内部处理锁定。

python
from multiprocessing import Process, Queue
def worker(q):
    q.put('Data from worker')
if __name__ == '__main__':
    q = Queue()
    p = Process(target=worker, args=(q,))
    p.start()
    print(q.get())
    p.join()

管道

Pipe 创建双向通信通道。send 和 recv 通过 pickling 传输 Python 对象。对于点对点通信,Pipe 比 Queue 更快。

python
from multiprocessing import Process, Pipe
def worker(conn):
    conn.send(['hello', 'world'])
    msg = conn.recv()
    conn.close()
if __name__ == '__main__':
    parent, child = Pipe()
    p = Process(target=worker, args=(child,))
    p.start()
    print(parent.recv())
    parent.send('acknowledged')
    p.join()

同步

Lock 确保一次只有一个进程访问共享资源。with lock 自动获取和释放。其他原语:RLock、Semaphore、Event。

python
from multiprocessing import Process, Lock
def safe_print(lock, msg):
    with lock:
        print(msg)
if __name__ == '__main__':
    lock = Lock()
    procs = [Process(target=safe_print, args=(lock, f'Task {i}'))
             for i in range(5)]
    for p in procs: p.start()
    for p in procs: p.join()
28

虚拟环境深入

venv 模块

venv 创建具有自己包目录的隔离 Python 环境。激活会修改 PATH。安装依赖前始终激活。

python
# Create
python -m venv myenv
# Activate (Linux/Mac)
source myenv/bin/activate
# Activate (Windows)
myenv\Scripts\activate
# Deactivate
deactivate

requirements.txt

requirements.txt 列出项目依赖。== 固定确切版本,>= 允许在范围内升级。始终提交到版本控制。

python
# Generate
pip freeze > requirements.txt
# Install
pip install -r requirements.txt
# Pin versions
flask==2.3.3
requests>=2.28.0,<3.0.0

Poetry

Poetry 是现代依赖管理器。pyproject.toml 替代 requirements.txt。虚拟环境自动管理。

python
# Initialize
poetry init
# Add dependency
poetry add flask
poetry add pytest --group dev
# Install all
poetry install
# Run command
poetry run python app.py

pipenv

pipenv 结合 pip 和 virtualenv。Pipfile 声明依赖,Pipfile.lock 固定确切版本。--dev 分离开发依赖。

python
# Create environment
pipenv install
# Add package
pipenv install requests
pipenv install pytest --dev
# Activate shell
pipenv shell
# Run command
pipenv run python app.py

Conda 环境

Conda 同时管理 Python 和非 Python 依赖。environment.yml 捕获完整环境。非常适合有二进制依赖的数据科学。

python
# Create
conda create -n myenv python=3.11
# Activate
conda activate myenv
# Export
conda env export > environment.yml
# Recreate
conda env create -f environment.yml
29

pip 高级用法

从 Git 安装

直接从 Git 仓库安装包。适用于未发布版本、分支或私有包。@branch 或 @commit 固定到特定版本。

python
# From GitHub
pip install git+https://github.com/user/repo.git
# Specific branch
pip install git+https://github.com/user/repo.git@branch-name
# Specific commit
pip install git+https://github.com/user/repo.git@abc123

可编辑安装

可编辑安装(-e)链接包而非复制。更改立即可用,无需重新安装。对包开发至关重要。

python
# Install in development mode
pip install -e .
# From a specific path
pip install -e /path/to/package
# With extras
pip install -e ".[dev,test]"

约束与哈希

约束限制可安装的版本。哈希检查验证包完整性,防止供应链攻击。

python
# constraints.txt
flask==2.3.3
pip install -c constraints.txt flask
# Hash checking
pip install --require-hashes -r requirements.txt

缓存管理

pip 缓存下载的 wheel。--no-cache-dir 强制重新下载。当缓存过大时清除以释放磁盘空间。

python
# Show cache info
pip cache info
# List cached packages
pip cache list
# Purge entire cache
pip cache purge
# Install with no cache
pip install --no-cache-dir flask

自定义索引

--index-url 指定自定义包仓库。--extra-index-url 添加回退。--trusted-host 为内部注册表绕过 SSL。

python
# Use custom index
pip install --index-url https://pypi.custom.com/simple/ flask
# Extra index (fallback)
pip install --extra-index-url https://pypi.custom.com/simple/ flask
# Trusted host (no SSL)
pip install --trusted-host pypi.custom.com flask
30

类型检查(mypy)

基本类型提示

类型提示注解函数参数和返回类型。Python 3.9+ 允许直接使用内置类型。提示启用使用 mypy 的静态分析。

python
def greet(name: str, times: int = 1) -> str:
    return (f"Hello, {name}! " * times).strip()
def process(data: list[int]) -> dict[str, int]:
    return {str(x): x for x in data}

Optional 与 Union

Optional[X] 等同于 X | None(Python 3.10+)。Union 类型允许多种可能类型。mypy 检查所有代码路径是否处理所有类型。

python
from typing import Optional
def find(items: list[int], target: int) -> int | None:
    for i, v in enumerate(items):
        if v == target: return i
    return None

泛型类型

泛型创建可重用的类型安全容器。TypeVar 定义类型变量,Generic 使类泛型化。mypy 确保类型一致性。

python
from typing import TypeVar, Generic
T = TypeVar('T')
class Stack(Generic[T]):
    def __init__(self) -> None:
        self._items: list[T] = []
    def push(self, item: T) -> None:
        self._items.append(item)
    def pop(self) -> T:
        return self._items.pop()

Protocol

Protocol 定义结构化子类型(带类型检查的鸭子类型)。任何具有所需方法的类都满足协议,无需继承。

python
from typing import Protocol
class Closeable(Protocol):
    def close(self) -> None: ...
def cleanup(resource: Closeable) -> None:
    resource.close()
class File:
    def close(self) -> None: print("Closed")
cleanup(File())  # OK - File has close()

mypy 配置

mypy.ini 配置类型检查严格度。strict 启用所有检查。按模块覆盖为测试或遗留代码放宽规则。

python
# mypy.ini
[mypy]
python_version = 3.11
strict = True
warn_return_any = True
disallow_untyped_defs = True
[mypy-tests.*]
ignore_errors = True
31

性能技巧

列表 vs 生成器

列表在内存中存储所有元素;生成器按需产生值。对于迭代一次的大型序列使用生成器。

python
# List: all in memory
squares = [x**2 for x in range(1000000)]
# Generator: lazy evaluation
squares_gen = (x**2 for x in range(1000000))
import sys
print(sys.getsizeof(squares))      # ~8MB
print(sys.getsizeof(squares_gen))  # ~200 bytes

字符串拼接

用 += 拼接字符串是 O(n^2)。join 是 O(n)。f-strings 是最快的插值方法。

python
# Slow: creates intermediate strings
result = ""
for s in parts:
    result += s
# Fast: join in one operation
result = "".join(parts)
# Fast: f-strings
msg = f"Hello, {name}!"

局部变量

局部变量查找比全局或属性查找更快。将常用函数赋值给局部变量可加速循环。

python
import math
# Slow: global lookup
def compute_slow(values):
    return [math.sqrt(v) for v in values]
# Fast: local reference
def compute_fast(values):
    sqrt = math.sqrt
    return [sqrt(v) for v in values]

__slots__

__slots__ 阻止 __dict__ 创建,每个实例节省 40-50% 内存。创建数百万对象时显著。不能添加未列出的属性。

python
class Point:
    __slots__ = ('x', 'y')
    def __init__(self, x, y):
        self.x = x
        self.y = y
p = Point(1, 2)
# p.z = 3  # AttributeError

timeit 与 cProfile

timeit 测量小代码片段的执行时间。cProfile 显示时间花在哪里。优化前使用分析找到实际瓶颈。

python
import timeit
t = timeit.timeit('sum(range(100))', number=10000)
print(f"{t:.4f}s")
import cProfile
cProfile.run('sum(x**2 for x in range(10000))')
32

常见陷阱

可变默认参数

默认参数值在定义时评估一次。可变默认值在所有调用间共享。始终使用 None 作为默认值。

python
# BUG: default list is shared
def add_item(item, lst=[]):
    lst.append(item)
    return lst
print(add_item(1))  # [1]
print(add_item(2))  # [1, 2]!
# FIX: use None
def add_item(item, lst=None):
    if lst is None: lst = []
    lst.append(item)
    return lst

闭包延迟绑定

闭包按引用捕获变量。当 lambda 被调用时,循环变量已有其最终值。默认参数捕获当前值。

python
# BUG: all print 2
funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])  # [2, 2, 2]
# FIX: default argument
funcs = [lambda i=i: i for i in range(3)]
print([f() for f in funcs])  # [0, 1, 2]

整数缓存

Python 缓存小整数。is 检查身份,== 检查相等性。永远不要用 is 进行值比较;is 仅用于 None、True、False。

python
# Small integers cached (-5 to 256)
a = 256; b = 256
print(a is b)  # True (cached)
c = 257; d = 257
print(c is d)  # False (not cached)
print(c == d)  # True

is vs ==

is 检查两个引用是否指向同一对象。== 检查两个对象是否具有相同值。is 仅用于 None、True、False。

python
a = [1, 2, 3]; b = [1, 2, 3]
print(a == b)  # True (same values)
print(a is b)  # False (different objects)
# Correct usage of is
if x is None: ...
if x is not None: ...

GIL

GIL 一次只允许一个线程执行 Python 字节码。线程对 I/O 密集型任务有效。CPU 密集型并行使用多进程。

python
# GIL prevents true parallelism for CPU-bound tasks
import threading
def cpu_work():
    total = sum(i**2 for i in range(10**7))
# Use multiprocessing for CPU work
from multiprocessing import Pool
with Pool(4) as p:
    p.map(cpu_work, range(4))

这篇内容对您有帮助吗?

学习路径

从零开始学习

通过结构化课程从头学习这个语言。