如何在Python中创建假值(Falsy)哨兵对象以简化函数参数判断?
问题描述
我有一个函数,要求调用时必须传入两个关键字参数中的一个。我使用哨兵对象(sentinel object)作为默认值,以确保无人直接调用func()而不传任何参数(这是明显的逻辑错误)。允许传入None作为参数值,此时函数不执行任何处理。
原代码如下:
NO_VALUE = object() def func(*, arg1 = NO_VALUE, arg2 = NO_VALUE): if arg1 is NO_VALUE and arg2 is NO_VALUE: raise ValueError("Pass in one of `arg1` or arg2`.") if arg1 is not NO_VALUE and arg1: # Do something with a truthy `arg1` value. if arg2 is not NO_VALUE and arg2: # Do something with a truthy `arg2` value.
能否简便地将NO_VALUE设置为假值(Falsy),从而将判断条件if arg1 is not NO_VALUE and arg1和if arg2 is not NO_VALUE and arg2简化为if arg1和if arg2?
我尝试将NO_VALUE设为空元组(),但发现任何空元组的id()似乎始终相同;也不想用空列表作为NO_VALUE,因为会触发关于可变默认值的代码检查警告。
可行方案
可以用自定义的假值哨兵类来实现,既满足假值特性,又能保证唯一性,不会和其他空值(比如()、None)混淆:
class NoValue: def __bool__(self): return False NO_VALUE = NoValue() def func(*, arg1=NO_VALUE, arg2=NO_VALUE): if arg1 is NO_VALUE and arg2 is NO_VALUE: raise ValueError("Pass in one of `arg1` or `arg2`.") if arg1: # 处理真值arg1的逻辑 print(f"Processing arg1: {arg1}") if arg2: # 处理真值arg2的逻辑 print(f"Processing arg2: {arg2}")
方案说明
- 自定义
NoValue类重写了__bool__方法,返回False,所以NO_VALUE是假值。直接用if arg1就能同时完成两个判断:如果arg1是NO_VALUE,if arg1会直接为False,跳过处理;如果是None或者其他假值(比如0、""),同样会跳过,完全符合需求。 - 每个
NoValue()实例都是唯一的,用is判断不会和其他值冲突,完美解决空元组()全局唯一的问题。 - 哨兵对象是不可变的,不会触发可变默认值的代码检查警告。
验证示例
func(arg1=123) # 输出 Processing arg1: 123 func(arg2=None) # 无输出(符合传入None不处理的要求) func(arg1="") # 无输出(空字符串是假值,不处理) func() # 抛出 ValueError: Pass in one of `arg1` or `arg2`.
内容的提问来源于stack exchange,提问作者ruohola
相关产品推荐
相关产品推荐

