如何在Python中实现类SQL NULL的三值逻辑?
实现SQL风格的三态布尔逻辑
这确实是个很贴合SQL场景的需求,我来帮你梳理下可行的方案:
为啥原生None满足不了需求?
Python里的and/or是基于真值测试的短路逻辑,和你要的SQL三值逻辑规则不完全匹配。比如你提到的None or False返回False,但按你给出的真值表,未知(N)OR 假(F)应该是未知(N),这就出现了不一致,所以用原生None肯定行不通。
Python的小限制:没法直接重载and/or
得提前说清楚:Python不允许重载and、or这种语言级别的短路运算符,只能重载&、|这类位运算符,不过not是可以通过__not__魔法方法重载的。所以我们得做一点小妥协,但完全能实现你要的逻辑。
基于标准库的实现方案
我们可以用Python标准库的enum.Enum来定义三态布尔类型,既简洁又符合你“优先用标准库”的要求,同时实现对应的逻辑运算:
from enum import Enum class TriBool(Enum): TRUE = True FALSE = False UNKNOWN = None def __and__(self, other): # 按你给的真值表实现AND逻辑 if not isinstance(other, TriBool): # 自动转换原生bool/None为TriBool实例 other = TriBool(other) if other is not None else TriBool.UNKNOWN lookup_table = { (TriBool.TRUE, TriBool.TRUE): TriBool.TRUE, (TriBool.TRUE, TriBool.UNKNOWN): TriBool.UNKNOWN, (TriBool.TRUE, TriBool.FALSE): TriBool.FALSE, (TriBool.UNKNOWN, TriBool.TRUE): TriBool.UNKNOWN, (TriBool.UNKNOWN, TriBool.UNKNOWN): TriBool.UNKNOWN, (TriBool.UNKNOWN, TriBool.FALSE): TriBool.FALSE, (TriBool.FALSE, TriBool.TRUE): TriBool.FALSE, (TriBool.FALSE, TriBool.UNKNOWN): TriBool.FALSE, (TriBool.FALSE, TriBool.FALSE): TriBool.FALSE, } return lookup_table[(self, other)] def __or__(self, other): # 按你给的真值表实现OR逻辑 if not isinstance(other, TriBool): other = TriBool(other) if other is not None else TriBool.UNKNOWN lookup_table = { (TriBool.TRUE, TriBool.TRUE): TriBool.TRUE, (TriBool.TRUE, TriBool.UNKNOWN): TriBool.TRUE, (TriBool.TRUE, TriBool.FALSE): TriBool.TRUE, (TriBool.UNKNOWN, TriBool.TRUE): TriBool.TRUE, (TriBool.UNKNOWN, TriBool.UNKNOWN): TriBool.UNKNOWN, (TriBool.UNKNOWN, TriBool.FALSE): TriBool.UNKNOWN, (TriBool.FALSE, TriBool.TRUE): TriBool.TRUE, (TriBool.FALSE, TriBool.UNKNOWN): TriBool.UNKNOWN, (TriBool.FALSE, TriBool.FALSE): TriBool.FALSE, } return lookup_table[(self, other)] def __not__(self): # NOT逻辑:取反,未知取反还是未知 if self is TriBool.TRUE: return TriBool.FALSE elif self is TriBool.FALSE: return TriBool.TRUE else: return TriBool.UNKNOWN def __bool__(self): # 这个方法影响if语句、原生and/or的短路行为,你可以按需调整 # 示例:把TRUE视为真,FALSE和UNKNOWN视为假 return self is TriBool.TRUE def __repr__(self): return self.name
用法示例
# 定义三态变量 t = TriBool.TRUE u = TriBool.UNKNOWN f = TriBool.FALSE # 测试AND运算 print(t & u) # 输出 UNKNOWN(对应T AND N=N) print(u & f) # 输出 FALSE(对应N AND F=F) # 测试OR运算 print(u | f) # 输出 UNKNOWN(对应N OR F=N) print(f | t) # 输出 TRUE(对应F OR T=T) # 测试NOT运算 print(not u) # 输出 UNKNOWN print(not t) # 输出 FALSE # 和原生类型交互 print(t & False) # 输出 FALSE print(u | None) # 输出 UNKNOWN # 用is判断状态 print(t is TriBool.TRUE) # 输出 True
额外优化:贴近自然语言的方法
如果你觉得&/|不够直观,可以给TriBool加两个方法:
def and_(self, other): return self & other def or_(self, other): return self | other
这样就能写成t.and_(u)、u.or_(f),更接近自然语言的逻辑表达。
这个方案完全基于标准库,不需要外部依赖,逻辑和你给出的真值表完全一致,也支持和原生bool/None的交互,应该能满足你的需求。
内容的提问来源于stack exchange,提问作者Artimis Fowl
相关产品推荐
相关产品推荐

