布尔人有两个可能的值。是否有三种可能值的类型?

2024-05-12 19:42:27 发布

您现在位置:Python中文网/ 问答频道 /正文

Possible Duplicate:
What's the best way to implement an 'enum' in Python?

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

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

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

    目前我想我会用一个整数(0表示“不”、1表示“不知道”和2表示“是”),但也许有更好的方法?整数似乎有点“神奇的数字”。

    我可以返回TrueFalseNone,但由于None的计算结果是False,在大多数比较上下文中,出现错误的时机似乎有点成熟。


Tags: thetononeanfalse类型状态整数
3条回答

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

class Ternary:
    FALSE = 0
    TRUE = 1
    UNKNOWN = 2

我自己,我可能会寻求你的解决方案(TrueFalseNone),但我理解你的担心。

与None并行的问题存在于false=0,true=1,unknown=2(unknown实际上也不是真的,但是如果不小心的话,它将被求值为true)。

我想出了一个老套的办法,至少能得到你想要的东西,我想。它至少可以为您提供在if/else和其他布尔求值实例中以三元方式求值的东西。

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)

用法:

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'

你可以做Yes,No,和未知的伪单子,这可以让你稍微改进eval。当你知道你的值将是yes或no时,你仍然可以进行简单的if检查,但是如果你试图在Unknown上直接执行bool()(即if 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))

用法:

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'

这样做的好处是允许nonzero在Unknown中作为spec调用工作,但它的缺点是从实例化开始就设置了Unknown的eval,并且不再允许Unknown成为伪单例。

在Python中,我会使用一个包含这三个值之一的包装器对象;我会使用TrueFalseNone。由于具有三个可能值的布尔类对象的隐式truthiness值是有问题的,我们将通过完全不允许这个(在__nonzero__(),或者在Python 3,__bool__()中引发异常)来解决这个问题,从而要求始终显式地进行比较,使用in==,或者!=。我们将把等式实现为identity,以便只匹配特定的singleton值TrueFalseNone

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

用法:

t = Tristate(True)
t == True           # True
t != False          # True
t in (True, False)  # True
bool(t)             # Exception!
if t: print "woo"   # Exception!

使用Tristate对象时,必须显式指定要匹配的值,即foo == True or bar != None。也可以通过foo in (False, None)来匹配多个值(当然,in两个值与!=一个值相反)。如果您希望能够对这些对象执行其他逻辑操作,则可以将它们作为方法实现,或者可能通过重写某些运算符来实现(遗憾的是,逻辑notandor不可重写,尽管还有a proposal要添加这些运算符)。

还要注意的是,在Python中不能重写id(),例如Tristate(None) is NoneFalse;这两个对象实际上是不同的。因为好的Python风格是在与singleton进行比较时使用is,这是不幸的,但不可避免的。

编辑4/27/16:添加了对将一个Tristate对象与另一个对象进行比较的支持。

相关问题 更多 >