在 Python 里,None 可能是调用者主动传入的值,所以不能用 None 来判断参数是否被提供。
在 Python 里,None
可能是调用者主动传入的值,所以不能用 None
来判断参数是否被提供。
使用 object()
生成一个特殊的 唯一标记变量,用作默认参数的占位符,就可以明确区分调用者是否真的传递了这个参数。
📌 为什么 None
不能区分调用者是否提供了参数?
来看下面的例子:
def dump_value(value, extra=None):
if extra is None:
print("调用方没有传递 extra 参数")
else:
print(f"调用方传递了 extra,值是:{extra}")
# 两种情况
dump_value(42) # ✅ 预期:调用方没传 extra
dump_value(42, None) # ❌ 但是这里 extra 也是 None
问题:
dump_value(42)
没有传extra
,函数内部extra=None
。dump_value(42, None)
调用者是主动传递了None
,但函数内extra
还是None
。- 函数内部根本无法区分这两种情况!
📌 解决方案:使用 _not_set = object()
思路:
object()
每次调用都会返回一个新的、独一无二的对象。- 但如果我们在全局定义
_not_set = object()
,它就是唯一的,可以作为“未设置参数”的标记值。
✅ 改进版代码
# 定义一个独一无二的标记变量
_not_set = object()
def dump_value(value, extra=_not_set):
if extra is _not_set: # ✅ 确保 extra 是未提供的情况
print("调用方没有传递 extra 参数")
else:
print(f"调用方传递了 extra,值是:{extra}")
# 测试
dump_value(42) # 输出:调用方没有传递 extra 参数
dump_value(42, None) # 输出:调用方传递了 extra,值是:None
dump_value(42, "hello") # 输出:调用方传递了 extra,值是:hello
📌 代码解析
_not_set = object()
定义了一个 唯一对象 作为默认值,占位。dump_value(value, extra=_not_set)
中:- 如果
extra
还是_not_set
,说明 调用者没传这个参数。 - 如果
extra
被赋值了(哪怕是None
),说明 调用者确实传了参数。
- 如果
- 这样,我们就能正确区分:
- 没传
extra
(参数采用默认值_not_set
)。 - 传了
extra=None
(调用者明确指定了None
)。
- 没传
📌 object()
为什么适合做默认值标记?
- 唯一性:
object()
每次调用都会生成 不同的对象,但_not_set = object()
只创建一次,保证它是唯一的。 - 不可伪造:不像
None
或False
,调用者无法轻易传入_not_set
这个值。 - 内存占用小:
object()
只是一个简单的 Python 内部对象,占用极小的内存。
🎯 总结
- 问题:如果默认参数用
None
,无法判断调用者是否真的传递了None
,还是没传参数。 - 解决方案:用
object()
创建一个唯一标记_not_set
作为默认参数。 - 好处:
- 确保只有调用者真的传入了参数,我们才会处理
extra
。 - 避免误判
None
,提高代码的健壮性和可读性。
- 确保只有调用者真的传入了参数,我们才会处理