Python函数默认参数在定义时求值一次,不会随模块级变量后续变化而更新;应使用None哨兵+运行时读取确保每次调用获取当前值。
可以,但必须注意:默认参数在函数定义时求值一次,不是每次调用时动态获取。如果你写 def f(x=MY_CONST):,且 MY_CONST 是模块级变量,那它确实会取定义时的值——但如果该常量后续被重新赋值(比如测试中 monkey patch),默认值不会变。
def f(x=CONFIG_TIMEOUT) 在 reload 后不更新?因为 Python 解析函数定义时,就执行了右侧表达式并把结果存进 __defaults__。即使 CONFIG_TIMEOUT 是个全局变量,它只被读取一次。
MAX_RETRY = 3)→ 直接用没问题API_BASE_URL)→ 默认参数会“冻结”初始值None 占位,内部做惰性读取None 作哨兵实现运行时取值这是最常用、最清晰的做法,确保每次调用都看到当前模块状态:
DEFAULT_TIMEOUT = 30def request(url, timeout=None): if timeout is None: timeout = DEFAULT_TIMEOUT
实际逻辑...
0 或 False 被当成“未提供”,必要时可用 object() 哨兵技术上可以,但没必要。例如用闭包生成函数:
def make_requester(timeout_const): def request(url, timeout=timeout_const): ... return request
request = make_requester(DEFAULT_TIMEOUT)
但这样增加了间接层,调试困难,且无法在模块顶层直接写 def request(...)。除非你明确需要“快照式配置”,否则纯属自找麻烦。
真正容易被忽略的是:很多人以为 import 重载后默认参数会刷新,其实不会——__defaults__ 是函数对象的一部分,跟模块对象解耦。改常量不等于改函数。