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

时间:2012-02-29 14:44:52

标签: python logic boolean

  

可能重复:
  What's the best way to implement an 'enum' in Python?

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

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

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

    目前我认为我会使用整数(0代表“不”,1代表“不知道”而2代表“是”),但也许还有更好的方法吗?整数似乎有点“神奇的数字”。

    我可以返回TrueFalseNone,但由于None在大多数比较环境中评估为False,因此错误似乎有点成熟

9 个答案:

答案 0 :(得分:32)

在Python中,我会使用包含这三个值之一的包装器对象来实现这一点。我会使用TrueFalseNone。由于具有三个可能值的类布尔对象的隐式真值是有问题的,我们将通过完全禁止它来解决这个问题(在__nonzero__()或Python 3中引发异常, __bool__()),因此要求始终使用in==!=明确进行比较。我们将等同作为标识实现,以便只匹配特定单例值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两个值与!=相反,只有一个值。如果您希望能够对这些对象执行其他逻辑操作,则可以将这些操作实现为方法,或者可能通过覆盖某些运算符(遗憾的是,逻辑notand和{ {1}}不可覆盖,但需要添加a proposal

另请注意,您无法在Python中覆盖or,例如id()Tristate(None) is None;这两个对象实际上是不同的。因为好的Python风格是在与单身人士比较时使用False,这是不幸的,但不可避免。

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

答案 1 :(得分:8)

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

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

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

答案 2 :(得分: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)

用法:

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和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))

用法:

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'

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

答案 3 :(得分:3)

  1. 至少有一种语言:C#int? num = null;,现在num实际上是Nullable<Int32>(问号是“语法糖”) 请参阅:http://msdn.microsoft.com/en-us/library/1t3y8s4s%28v=vs.80%29.aspxhttp://en.wikipedia.org/wiki/Nullable_type
  2. 不了解Python,但这取决于您的偏好:可用性(enumclass)与效率(4位字段)

答案 4 :(得分:2)

它通常被称为'enum',在该名称的C构造之后。

您可以轻松创建自己的类,其对象必须使用集合中的值进行初始化,并且可以相应地创建适当的比较,相等和真值函数。

答案 5 :(得分:1)

我的dbf module中有一个3值逻辑类。

它将False / True / Unknown实现为单例值Falsth / Truth / Unknown。它实现了所有的比较运算符,并且还允许与Python单例False / True / NoneNone进行比较,意思是未知)。与Unknown值的任何比较都会产生Unknown,并且尝试在Unknown语句(或其他if上下文)中隐式使用bool值虽然可以在布尔上下文中使用TypeErrorTruth,但可以提升Falsth,并且Unknown可以直接进行比较。

由于无法覆盖andornot行为,因此该类型会覆盖按位运算符&|和{ {1}}。

它还实现了~__index__的值为Unknown

示例:

2

答案 6 :(得分:0)

没有这样的内置类型。枚举也不支持作为一种类型。但是,您可以使用常量:

class Option:
    NO = 0
    DONT_KNOW = 1
    YES = 2

reply = Option.YES

答案 7 :(得分:0)

我不是一个Python编程,但你可以在不知道的情况下返回None。来电者必须检查“是”,“否”或无,但至少他们会知道你不知道。

http://boodebr.org/main/python/tourist/none-empty-nothing

答案 8 :(得分:0)

我从未见过类似boolean的类型,它有两个以上的值。毕竟“布尔”意味着该函数在“布尔域”上运行,而“布尔域”又具有正好2个值。

也就是说,使用整数,枚举甚至字符串都是完全可以的。在python中,您可以创建一个仅包含变量YES,NO,MAYBE的模块,并从那里导入到其他所有位置。