关于python:布尔有两个可能的值。

Booleans have two possible values. Are there types that have three possible values?

本问题已经有最佳答案,请猛点这里访问。

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

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

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

  • 在没有这种类型的语言中(比如python),最好的类型是什么?

    现在我想我用一个整数(0表示"不",1表示"不知道",2表示"是"),但也许有更好的方法?整数看起来有点"神奇数字"。

    我可以返回TrueFalseNone,但由于None会对False进行评估,在大多数比较情况下,它似乎有点成熟,容易出错。


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    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

    用途:

    1
    2
    3
    4
    5
    6
    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不是可重写的,尽管有一个建议要添加它)。

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

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


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

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

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


    与"无"问题平行存在,错误=0,正确=1,未知=2(未知也不是真正的,但如果不小心,将评估为真)。

    我想,我想出了一个老套的方法来得到至少接近你想要的东西。它至少会为您提供一些东西,在if/else和其他布尔值eval实例中以三元形式进行评估。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    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)

    用途:

    1
    2
    3
    4
    5
    6
    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'

    你可以做是,否,和未知的伪单例,这会让你改进eval一点。当你知道你的值将是"是"或"否"时,你仍然可以做简单的if检查,但是如果你试图在未知的情况下做一个直接的bool()(即如果x),你会得到一个类型错误。这将使您的代码更加明确,因为每次检查三元类型的值时,您都必须在代码中定义如何在该条件的上下文中处理未知项,因此这将是一个加号。

    编辑:我想到了一个替代方案,它需要更少的特殊处理,但灵活性较差。上周四更改:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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))

    用途:

    1
    2
    3
    4
    5
    6
    7
    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'

    这样做的好处是允许非零按照规范在未知中的要求工作,但是它有一个缺点,那就是从实例化开始对未知集进行评估,并且不再允许未知集是一个伪单例。


  • 至少有一种语言是这样的:C#int? num = null;,现在num实际上是Nullable(问号是一种"句法糖")。请参阅:http://msdn.microsoft.com/en-us/library/1t3y8s4s%28v=vs.80%29.aspx和http://en.wikipedia.org/wiki/nullable_type
  • 不知道python,但它取决于您的喜好:可用性(enumclass与效率(4位字段)

  • 它通常被称为"枚举",位于该名称的C构造之后。

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


    我的DBF模块中有一个3值逻辑类。

    它将False/True/Unknown作为单值Falsth/Truth/Unknown来实现。它实现了所有的比较运算符,还允许与python singletons False/True/None(None表示未知)。任何与Unknown值的比较都会导致Unknown的结果,并且试图在if语句(或其他bool上下文)中隐式使用Unknown值会提高TypeError,尽管TruthFalsth可以在布尔上下文中使用,并且可以直接与Unknown进行比较。

    由于无法重写andornot行为,因此类型重写按位运算符&|~

    它还实现了__index__Unknown的值为2

    例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    from dbf import Logical, Truth, Falsth, Unknown

    middle_name = raw_input("What is the middle name? ['?' if unknown]").strip()
    if middle_name == '?':
        middle_name = ''
        middle_exists = Unknown
    elif middle_name:
        middle_exists = Truth
    else:
        middle_exists = Falsth
    .
    .
    .
    if middle_exists is Unknown:
        print"The middle name is unknown."
    elif middle_exists:
        print"The middle name is %s." % middle_name
    else:
        print"This person does not have a middle name."


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

    也就是说,使用整数、枚举甚至字符串是完全可以的。在python中,您可以创建一个只包含变量yes、no和maybe的模块,并从那里导入到其他地方。


    我不太喜欢Python编程,但是在不知道的情况下,你能不返回一个吗?打电话的人必须检查"是"、"否"或"无",但至少他们会知道你不知道。

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


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

    1
    2
    3
    4
    5
    6
    class Option:
        NO = 0
        DONT_KNOW = 1
        YES = 2

    reply = Option.YES