NOTE目录骨架来自菜鸟教程 Python3 函数与异常相关章节,表述与细节对照 Python 官方文档 与相关 PEP 核对。基于 Python 3。完整出处见文末 参考。
iter 与 next
迭代器实现迭代器协议:__iter__() 返回自身(或另一迭代器),该对象再提供 __next__()。内置 iter() 优先调用 __iter__();若没有 __iter__ 但实现了从 0 开始的 __getitem__,仍可按序列方式迭代(见 iterator protocol)。日常自己写可迭代对象时,实现 __iter__ 即可。
next(iterator[, default]) 调用 iterator.__next__()。没有更多元素时,__next__() 抛出 StopIteration;若提供了 default,则返回 default 而不抛异常。
容器(如 list)本身通常不是迭代器,但可迭代(iterable):__iter__() 返回一个新的迭代器。每次 for x in lst: 都会先 iter(lst) 再反复 next。
it = iter([10, 20, 30])print(next(it)) # 10print(next(it)) # 20print(next(it, "没了")) # 30print(next(it, "没了")) # 没了for 循环在底层等价于:取迭代器 → 反复 next → 捕获 StopIteration 结束。自己实现可迭代对象时,最小骨架如下(菜鸟 迭代器 有类似例子,协议以官方为准):
class CountDown: def __init__(self, n): self.n = n
def __iter__(self): return self
def __next__(self): if self.n <= 0: raise StopIteration self.n -= 1 return self.n + 1生成器与 yield
生成器是一种迭代器,由含 yield 的函数或 yield from 表达式产生。调用生成器函数不会立刻执行函数体,而是返回一个生成器对象;每次 next() 或 for 循环驱动执行到下一个 yield,产出值并暂停。
def count_up_to(n): i = 1 while i <= n: yield i i += 1
for x in count_up_to(3): print(x) # 1, 2, 3生成器表达式 (x * x for x in range(5)) 语法类似列表推导,但结果是生成器而非列表,适合大数据或流水线,见 Generator expressions。
yield from iterable 把产出委托给另一个可迭代对象,常用于扁平化嵌套生成器。要用 with 包一层生成器,需 contextlib.contextmanager;生成器本身不是上下文管理器。
定义函数 def
def 定义用户函数。函数体在调用时才执行;定义时只创建函数对象并绑定名字。函数是一等对象,可赋给变量、当参数、当返回值。
def greet(name): """向 name 问好。""" return f"Hello, {name}!"
print(greet("Alice"))print(greet.__name__) # greet教程 · Defining Functions 强调:函数可 return 多个值(实际是返回一个元组),也可无 return(等价于 return None)。
参数:位置、默认、关键字、*args、**kwargs
参数种类见 More on Defining Functions 与 Function definitions。
位置参数(positional):按定义顺序传入。
默认参数(default):形参带 = 默认值;缺省调用时使用默认值。默认值在函数定义时只求值一次——不要用可变对象(如 []、{})当默认值,否则多次调用会共享同一对象:
def bad(a, items=[]): # 反例 items.append(a) return items
def good(a, items=None): if items is None: items = [] items.append(a) return items仅关键字参数(keyword-only):在 * 或 *args 之后的参数必须用关键字传入;PEP 3102 起可在签名里写 *, x, y。
关键字参数(keyword):func(a=1, b=2) 按名字传参,顺序可与定义不同。
*args:收集多余位置实参为元组。**kwargs:收集多余关键字实参为字典。名字只是约定,可以是 *rest、**opts。
def demo(pos, /, both, *, kwonly, **kwargs): # pos: 仅位置(3.8+ 语法 /) # both: 位置或关键字 # kwonly: 仅关键字 # kwargs: 其余关键字 print(pos, both, kwonly, kwargs)
demo(1, 2, kwonly=3, extra=4)# demo(pos=1, ...) 会 TypeError:pos 不能按关键字调用侧 *iterable 解包位置实参,**mapping 解包关键字实参(键须为字符串)。
return
return 结束当前函数调用,可选跟一个表达式。无表达式时返回 None。return 可在任意缩进层级结束函数,不会自动结束外层循环(与某些语言不同)。
def find_first(pred, items): for x in items: if pred(x): return x return Nonelambda
lambda 产生匿名函数对象,语法 lambda 参数: 表达式。只能写单个表达式,不能含语句或赋值(3.8+ 海象 := 在 lambda 里仍受限)。适合短小的回调,复杂逻辑用 def。
pairs = [(2, "b"), (1, "a"), (3, "c")]pairs.sort(key=lambda p: p[0])LEGB:名字怎么找
命名与绑定 规定:名字引用按 LEGB 顺序查找——Local(当前函数)、Enclosing(外层函数)、Global(模块全局)、Built-in(内置名,如 len)。
x = "global"
def outer(): x = "enclosing"
def inner(): x = "local" print(x) # local
inner() print(x) # enclosing
outer()print(x) # global函数定义在定义时绑定外层作用域(闭包),不是调用时。内层函数可读取外层名字;若要重新绑定外层非全局名字,需要 nonlocal;绑定模块级名字需要 global。
if / for / while / try 不创建函数那样的局部作用域,块里赋的名在块外仍能用(菜鸟 命名空间 有图;语义以 Naming and binding 为准)。
内置名在 builtins 模块:import builtins; dir(builtins)。
global 与 nonlocal
global 把本函数里的名字标成模块全局。nonlocal 标成最近一层外层函数里的名字(不能是全局)。
函数体内只要出现对某名字的赋值,整个函数都把它当局部。因此下面会 UnboundLocalError:
x = 1
def f(): print(x) # 想读全局 x x = 2 # 这一行让 x 在整个 f 里都是局部要改全局就写 global x,或不要在函数里给同名赋值。
count = 0
def inc_global(): global count count += 1
def make_counter(): n = 0
def inc(): nonlocal n n += 1 return n
return inc
c = make_counter()print(c(), c()) # 1, 2inc_global()print(count) # 1滥用 global 会让数据流难追踪;优先用参数、返回值或类封装状态。
装饰器
PEP 318 引入函数装饰器语法:@decorator 放在 def(或 class)前,等价于 func = decorator(func)。装饰器通常是接受 callable、返回 callable 的可调用对象。
def log_calls(fn): def wrapper(*args, **kwargs): print(f"calling {fn.__name__}") return fn(*args, **kwargs) return wrapper
@log_callsdef add(a, b): return a + b
add(1, 2) # 先打印 calling add,再返回 3被包装后 wrapper.__name__ 等元数据会丢;用 functools.wraps 拷回去:
import functools
def log_calls(fn): @functools.wraps(fn) def wrapper(*args, **kwargs): print(f"calling {fn.__name__}") return fn(*args, **kwargs) return wrapper带参装饰器:外层函数先接收装饰器参数,返回真正的装饰器。
def repeat(times): def decorator(fn): def wrapper(*args, **kwargs): for _ in range(times): result = fn(*args, **kwargs) return result return wrapper return decorator
@repeat(3)def hi(): print("hi")类也可以当装饰器(实现 __call__)。内置装饰器如 staticmethod、classmethod、property 在第 8 篇类一节会碰到。装饰器栈从下往上应用:@a @b def f 等价于 f = a(b(f))。
with 与上下文管理器
with 语句用于管理资源:进入时 setup,离开时 teardown,即使发生异常也会清理。PEP 343 定义协议。
上下文管理器需实现:
__enter__(self):进入with块前调用;返回值绑定到as后的变量(若无as则忽略返回值)。__exit__(self, exc_type, exc_val, exc_tb):离开with块时调用。若返回真值,会抑制当前异常(一般不这么做);否则异常继续传播。
class Tag: def __init__(self, name): self.name = name
def __enter__(self): print(f"<{self.name}>") return self
def __exit__(self, exc_type, exc, tb): print(f"</{self.name}>") return False
with Tag("p") as t: print("body")内置 open() 返回的文件对象、threading.Lock 等已实现该协议。手写资源管理可用 contextlib.contextmanager 装饰生成器,或用 contextlib.AbstractContextManager。多个上下文管理器可写 with A() as a, B() as b:。
try / except / else / finally
完整语法见 The try statement 与 Errors and Exceptions。
try: risky()except ValueError as e: handle(e)except (TypeError, OSError): recover()else: # 仅当 try 块未抛出异常时执行 on_success()finally: # 总是执行(除非进程被杀死等) cleanup()要点:
except:匹配异常类型(元组表示多个)。as e绑定异常实例;在 Python 3 里,except块结束后e会被删除,避免循环引用(PEP 3110)。else:没有异常时运行,常把可能抛错的逻辑放在try、成功路径放在else,避免把else里的错误当成except能处理的同一类问题(教程建议)。finally:用于释放资源;若有return,finally仍会在返回前执行。- 顺序:
try→ 若异常则匹配的except→ 无异常则else→ 始终finally。
raise 抛出异常:raise ValueError("msg");raise 单独使用则重新抛出当前异常(常在 except 里记录后再抛)。
def parse_int(s): try: return int(s) except ValueError: raise ValueError(f"不是整数: {s!r}") from None # 抑制异常链Exception chaining:内层 raise ... from e 保留原因;from None 隐藏上下文。
用户自定义异常:继承 Exception(不要直接继承 BaseException,除非做系统退出类异常)。
class MyAppError(Exception): passassert 用于调试断言,-O 优化模式下会被去掉;不要用 assert 做业务校验或数据验证。
常见内置异常(点名)
下列名字均来自 Built-in Exceptions,日常读写代码时最常见。完整继承树见文末附录。
| 异常 | 典型触发场景 |
|---|---|
Exception | 几乎所有用户可捕获异常的基类 |
StopIteration | 迭代器没有更多元素(next / for 结束) |
StopAsyncIteration | 异步迭代器结束 |
ArithmeticError | 算术错误分支的基类 |
FloatingPointError | 浮点运算失败(极少见,依赖平台) |
OverflowError | 数值结果太大 |
ZeroDivisionError | 除法或取模除零 |
AssertionError | assert 失败 |
AttributeError | 属性不存在或无法设置 |
EOFError | input() 在无数据可读时(如 Ctrl+D) |
ImportError | import 失败 |
ModuleNotFoundError | 找不到模块(ImportError 子类) |
LookupError | 索引/键错误的基类 |
IndexError | 序列下标越界 |
KeyError | 字典键不存在 |
MemoryError | 内存不足 |
NameError | 未定义的名字 |
UnboundLocalError | 局部名字在赋值前被引用 |
OSError | 系统 / I/O 相关(IOError 是其别名) |
FileNotFoundError | 文件不存在 |
PermissionError | 权限不足 |
RecursionError | 超过最大递归深度 |
ReferenceError | 弱引用对象已销毁(少见) |
RuntimeError | 一般不落在更具体类型时的运行时错误 |
NotImplementedError | 抽象方法 / 待实现 |
SyntaxError | 语法错误(编译期) |
IndentationError | 缩进错误 |
TabError | Tab 与空格混用 |
SystemError | 解释器内部错误 |
TypeError | 类型不对或参数个数不对 |
ValueError | 类型对但值不合法(如 int("abc")) |
UnicodeError | Unicode 编解码相关基类 |
UnicodeDecodeError / UnicodeEncodeError | 解码 / 编码失败 |
Warning | 警告类别基类(不是 Exception 同级习惯捕获对象) |
一般不捕获 BaseException 下的 KeyboardInterrupt、SystemExit、GeneratorExit,除非在做框架级顶层处理。
附录:内置异常继承关系(节选)
以下为官方文档 Exception hierarchy 的压缩表,便于查「该捕哪个父类」。缩进表示子类。
| 基类 | 直接子类(节选) |
|---|---|
BaseException | SystemExit, KeyboardInterrupt, GeneratorExit, Exception |
Exception | StopIteration, StopAsyncIteration, ArithmeticError, AssertionError, AttributeError, BufferError, EOFError, ImportError, LookupError, MemoryError, NameError, OSError, ReferenceError, RuntimeError, SyntaxError, SystemError, TypeError, ValueError, Warning |
ArithmeticError | FloatingPointError, OverflowError, ZeroDivisionError |
LookupError | IndexError, KeyError |
OSError | BlockingIOError, ChildProcessError, ConnectionError, FileExistsError, FileNotFoundError, InterruptedError, IsADirectoryError, NotADirectoryError, PermissionError, ProcessLookupError, TimeoutError … |
ConnectionError | BrokenPipeError, ConnectionAbortedError, ConnectionRefusedError, ConnectionResetError |
ImportError | ModuleNotFoundError |
NameError | UnboundLocalError |
RuntimeError | NotImplementedError, RecursionError |
SyntaxError | IndentationError → TabError |
UnicodeError | UnicodeDecodeError, UnicodeEncodeError, UnicodeTranslateError |
ValueError | UnicodeError 等 |
捕获时:except OSError 可捕 FileNotFoundError;except LookupError 可捕 IndexError 与 KeyError。具体是否捕获取决于你是否能合理处理。
附录:函数参数汇总
| 写法 | 含义 |
|---|---|
def f(a, b) | 位置或关键字 |
def f(a, b=0) | b 有默认值 |
def f(a, /, b) | a 仅位置(3.8+) |
def f(a, *, b) | b 仅关键字 |
def f(*args) | 多余位置 → 元组 |
def f(**kwargs) | 多余关键字 → 字典 |
def f(a, /, b, *args, c=1, **kw) | 顺序:仅位置、/、位置或关键字、*args、仅关键字、**kwargs |
参考
官方文档(中文版 可对照阅读):
- More Control Flow Tools — Defining Functions — 默认参数、关键字参数、
*args/**kwargs、Docstring - More Control Flow Tools — Intermezzo: Coding Style — 命名与可读性(与函数组织相关)
- Errors and Exceptions — 异常处理、
else/finally、raise、用户异常、异常链 - Compound statements — Function definitions — 完整参数语法、
lambda不能替代def的全部能力 - Compound statements — The try statement —
try/except/else/finally语义 - Compound statements — The with statement —
with与as - Data model — With Statement Context Managers —
__enter__/__exit__ - Glossary — iterator / generator / iterable — 术语定义
- Execution model — Naming and binding — LEGB、闭包
- Simple statements — global / nonlocal / return / raise / yield
- Built-in Exceptions — 异常列表与继承树
- functools.wraps — 装饰器保留元数据
- contextlib — 上下文管理器工具
PEP:
- PEP 318 — Decorators for Functions and Methods
- PEP 343 — The “with” Statement
- PEP 3102 — Keyword-Only Arguments
- PEP 3110 — Catching exceptions in Python 3000
目录来源(骨架,不以它为准改语法):