使用contextlib.suppress替代嵌套try/else时遇UnboundLocalError的解决方法
用contextlib.suppress替代嵌套try/except的正确姿势
为遵循flake8规范,尝试用contextlib.suppress替代嵌套try/except结构获取模型的early_stopping_rounds(早停轮数),但改写后出现UnboundLocalError: local variable 'n_rounds' referenced before assignment错误,以下是问题分析和正确用法:
原函数(可正常工作)
def _get_early_stopping_rounds(model, **kwargs) -> int: """Returns the number of early stopping rounds.""" try: n_rounds = kwargs["early_stopping_rounds"] except Exception: try: n_rounds = model.get_params()["early_stopping_rounds"] except Exception: try: n_rounds = None except Exception: pass return n_rounds
该函数优先从kwargs中取值,失败则尝试从model.get_params()获取,仍失败则返回None,示例调用返回20。
错误的改写版本
from contextlib import suppress def _get_early_stopping_rounds(model, **kwargs) -> int: """Returns the number of early stopping rounds.""" with suppress(Exception): n_rounds = kwargs["early_stopping_rounds"] with suppress(Exception): n_rounds = model.get_params()["early_stopping_rounds"] with suppress(Exception): n_rounds = None return n_rounds
错误原因
- 嵌套的
with suppress是串行执行:只有前一个赋值成功,才会进入下一个with块;如果所有赋值操作都触发异常,n_rounds从未被定义,返回时就会抛出未绑定变量的错误。 - 原函数的第三个try完全多余,因为
n_rounds = None不会抛出任何异常。
正确的改写方式
先给n_rounds设置默认值,再用独立的with suppress依次尝试不同的赋值来源,逻辑和原函数一致:
from contextlib import suppress def _get_early_stopping_rounds(model, **kwargs) -> int: """Returns the number of early stopping rounds.""" n_rounds = None # 初始化默认值,避免未绑定错误 # 优先尝试从kwargs获取 with suppress(Exception): n_rounds = kwargs["early_stopping_rounds"] # kwargs获取失败时,尝试从model参数中获取 with suppress(Exception): n_rounds = model.get_params()["early_stopping_rounds"] return n_rounds
逻辑说明
- 先初始化
n_rounds为None,确保无论后续操作是否成功,变量都已绑定。 - 每个
with suppress块独立尝试一种赋值方式:如果kwargs中存在目标值,就覆盖默认值;如果失败,保持当前值(默认的None),再尝试从model.get_params()中获取,成功则覆盖,失败则保留之前的值。 - 去掉了原函数中多余的第三个try块,因为赋值
None不会触发异常。
内容的提问来源于stack exchange,提问作者Jake Niederer
相关产品推荐
相关产品推荐

