布尔有两个可能的价值观.是否存在具有三种可能值的类型?

Pau*_*ite 37 python logic boolean

可能重复:
在Python中实现'枚举'的最佳方法是什么?

我正在编写一个函数,理想情况下,我想返回三种状态之一:"是","否"和"不知道".

  1. 任何编程语言的类型都有三种,只有三种状态吗?像布尔值,但有三个状态而不是两个?

  2. 在没有这种类型的语言(如Python)中,表示这种类型的最佳类型是什么?

    目前我认为我将使用整数(0"不",1"不知道"和2"是"),但也许有更好的方法?整数似乎有点"神奇的数字".

    我可以回来True,False或者None,正如在大多数比较环境中None评估的那样False,错误似乎有点成熟.

kin*_*all 34

在Python中,我会使用包含这三个值之一的包装器对象来做到这一点; 我会使用True,FalseNone.由于具有三个可能值的类布尔对象的隐式真值是有问题的,我们将通过完全禁止它(__nonzero__()在Python 3中引发异常,或在Python 3中__bool__())来解决这个问题,因此要求总是明确地进行比较,使用in,==!=.所以只有特定的单值,我们将实现平等的身份True,False以及None相匹配.

class Tristate(object):

    def __init__(self, value=None):
       if any(value is v for v in (True, False, None)):
          self.value = value
       else:
           raise ValueError("Tristate value must be True, False, or None")

    def __eq__(self, other):
       return (self.value is other.value if isinstance(other, Tristate)
               else self.value is other)

    def __ne__(self, other):
       return not self == other

    def __nonzero__(self):   # Python 3: __bool__()
       raise TypeError("Tristate object may not be used as a Boolean")

    def __str__(self):
        return str(self.value)

    def __repr__(self):
        return "Tristate(%s)" % self.value
Run Code Online (Sandbox Code Playgroud)

用法:

t = Tristate(True)
t == True           # True
t != False          # True
t in (True, False)  # True
bool(t)             # Exception!
if t: print "woo"   # Exception!
Run Code Online (Sandbox Code Playgroud)

使用Tristate对象时,必须明确指定要匹配的值,即foo == True or bar != None.您还foo in (False, None)可以匹配多个值(当然,in两个值!=与单个值相反).如果有其他的逻辑运算,你希望能够与这些对象进行,你可以为方法,或者可能通过重写某些运营商(实现这些可悲的是,然而,逻辑not,andor不覆写投放,但有一个建议,以添加).

还要注意的是,你不能覆盖id()在Python,所以如Tristate(None) is NoneFalse; 这两个对象实际上是不同的.因为is在与单身人士比较时使用好的Python风格,这是不幸的,但不可避免.

编辑2016年4月27日:添加了将一个Tristate对象与另一个对象进行比较的支持.

  • 有关PyPI上也提供的更完整的实现,请查看[Python tribool模块](http://www.grantjenks.com/docs/tribool/).(我会发布这个作为答案,但不允许.) (3认同)
  • 更新了一些Python 3的详细信息.谢谢接受我的回答,我当然不期待它! (2认同)
  • 如果它只有一个问题,那么,对于一些我在10分钟内完成的代码并且仅对...进行最小测试也不错:(-) (2认同)

Lin*_*iel 8

这称为三元逻辑或三值逻辑.正如其他答案所示,您可以实现一个类:

class Ternary:
    FALSE = 0
    TRUE = 1
    UNKNOWN = 2
Run Code Online (Sandbox Code Playgroud)

我自己,我可能会去为你的解决方案(True,False,None),但我明白您的顾虑.


Sil*_*Ray 6

与None问题并行存在,false = 0,true = 1,unknown = 2(未知也不是真的,但如果你不小心,则eval为True).

我认为,我想出了一种至少接近你想要的东西的hackish方式.它至少会让你在if/else和其他布尔eval实例中以三进制方式进行评估.

class Yes(object):
    def __nonzero__(self):
        return True

class No(object):
    def __nonzero__(self):
        return False

class Unknown(object):
    def __nonzero__(self):
        raise ValueError('Unknown typed values do not evaluate to True/False.  Try using Ternary.eval().')

class Ternary(object):
    def __init__(self, yes, no, unknown):
        setattr(self, yes, Yes())
        setattr(self, no, No())
        setattr(self, unknown, Unknown())
    @staticmethod
    def eval(value, unknown_eval):
        if isinstance(value, Unknown):
            return unknown_eval
        return bool(value)
Run Code Online (Sandbox Code Playgroud)

用法:

t = Ternary('yes', 'no', 'unknown')
# Do stuff to assign ternary value to x
if Ternary.eval(x, True):
    print 'x is yes or unknown'
if Ternary.eval(x, False):
    print 'x is yes only'
Run Code Online (Sandbox Code Playgroud)

你可以制作Yes,No和Unknown伪单例,它们可以让你稍微改进eval.如果你知道你的值是肯定的或者没有,你仍然可以做简单的检查,但如果你试图在未知的情况下做一个直的bool()(即如果是x),你会得到一个TypeError.这会使你的代码更加明确,因为每次你检查三元型的值时,你必须在你的代码中定义你想要在那个条件的上下文中处理未知的内容,这样会更好.

编辑:我想到了一种替代方案,需要较少的特殊处理但不太灵活.如此改变:

class Unknown(object):
    def __init__(self, eval):
        self._eval = eval
    def __nonzero__(self):
        return self._eval

class Ternary(object):
    def __init__(self, yes, no, unknown, unknown_eval):
        setattr(self, yes, Yes())
        setattr(self, no, No())
        setattr(self, unknown, Unknown(unknown_eval))
Run Code Online (Sandbox Code Playgroud)

用法:

t1 = Ternary('yes', 'no', 'unknown', True)
t2 = Ternary('yes', 'no', 'unknown', False)
# Do stuff to assign ternary values to x1 and x2
if x1:
    print 'x is yes or unknown'
if x2:
    print 'x is yes only'
Run Code Online (Sandbox Code Playgroud)

这样做的好处是允许非零作为未知的规范调用,但它有一个缺点,即从实例化中将未知的eval设置为石头并且不再允许Unknown为伪单例.