Los booleanos tienen dos valores posibles. ¿Hay tipos que tienen tres valores posibles?

Posible duplicado:
¿Cuál es la mejor manera de implementar un ‘enum’ en Python?

Estoy escribiendo una función que, idealmente, me gustaría devolver uno de los tres estados: “sí”, “no” y “no sé”.

  1. ¿Algún lenguaje de progtwigción tiene un tipo que tiene tres, y solo tres estados? Como un booleano, pero con tres estados en lugar de dos?

  2. En los idiomas que no tienen ese tipo (como Python), ¿cuál es el mejor tipo para representar esto?

    Actualmente creo que optaré por un número entero ( 0 para “no”, 1 para “no sé” y 2 para “sí”), pero ¿tal vez hay una mejor manera? Los enteros parecen un poco “número mágico”.

      Podría devolver True , False o None , pero como None evaluaría False en la mayoría de los contextos de comparación, parece un poco maduro para los errores.

    En Python, lo haría con un objeto envoltorio que contiene uno de esos tres valores; Yo usaría True , False y None . Dado que el valor de veracidad implícito de un objeto de tipo booleano con tres valores posibles es problemático, lo resolveremos __nonzero__() por completo (generando una excepción en __nonzero__() , o en Python 3, __bool__() ), por lo que se requieren comparaciones Siempre se debe hacer explícitamente, usando in , == , o != . Implementaremos la igualdad como identidad de modo que solo coincidan los valores singleton específicos True , False y 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 

    Uso:

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

    Al usar objetos Tristate , debe especificar explícitamente qué valores se deben coincidir, es decir, foo == True or bar != None . También puede hacer foo in (False, None) para hacer coincidir varios valores (aunque, por supuesto, in dos valores es el opuesto a != Con un solo valor). Si hay otras operaciones lógicas que desea poder realizar con estos objetos, podría implementarlos como métodos, o posiblemente anulando a ciertos operadores (lamentablemente, sin embargo, lógicamente not , and / or no son anulables, aunque hay una propuesta para añadir que).

    También tenga en cuenta que no puede anular id() en Python, por lo que, por ejemplo, Tristate(None) is None is False ; Los dos objetos son de hecho diferentes. Dado que el buen estilo de Python es usar cuando se compara con singletons, esto es desafortunado, pero inevitable.

    Editar 4/27/16: Se agregó soporte para comparar un objeto Tristate con otro.

    Esto se llama lógica ternaria o lógica de tres valores. Como sugieren otras respuestas, podría implementar una clase:

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

    Yo mismo, probablemente buscaría su solución ( True , False , None ) pero entiendo su preocupación.

    El paralelo con el problema Ninguno existe con falso = 0, verdadero = 1, desconocido = 2 (lo desconocido tampoco es cierto, pero se evaluará como Verdadero si no tiene cuidado).

    Se me ocurrió una forma pirateada de obtener algo que al menos se aproxima a lo que quieres, creo. Al menos obtendrá algo que se evaluará de forma trinaria en if / else y otras instancias de evaluación booleanas.

     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) 

    Uso:

     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' 

    Podrías hacer Sí, No y Pseudo-singletons Desconocidos que te permitirían refinar la evaluación un poco. Aún puede hacer algo simple si lo comprueba cuando sabe que su valor va a ser sí o no, pero si intenta hacer un bool directo () (es decir, si x) en Desconocido, obtendrá un error TypeTrror. Sin embargo, esto haría que su código fuera más explícito, ya que cada vez que verificara un valor del tipo trinario, tendría que definir en su código la forma en que deseaba que lo desconocido se tratara en el contexto de ese condicional, por lo que sería una ventaja. .

    Edición: pensé en una alternativa que requeriría menos manejo especial pero menos flexible. Alterar de esta manera

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

    Uso:

     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' 

    Esto tiene la ventaja de permitir que el no cero funcione como lo requiere la especificación en Desconocido, pero tiene la desventaja de tener la evaluación de Desconocido en piedra desde la creación de instancias y de no permitir que Desconocido sea un pseudo-singleton.

    1. Al menos un idioma tiene esto: C# : int? num = null; int? num = null; , ahora num es en realidad Nullable (el signo de interrogación es un “azúcar sintáctica”) consulte: http://msdn.microsoft.com/en-us/library/1t3y8s4s%28v=vs.80%29.aspx y http://en.wikipedia.org/wiki/Nullable_type
    2. No sé Python, pero depende de tu preferencia: usabilidad ( enum o class ) vs. eficiencia (campos de 4 bits)

    Generalmente se conoce como ‘enumeración’, después de la construcción C de ese nombre.

    Puede crear fácilmente su propia clase, cuyos objetos deben inicializarse con valores de un conjunto, y puede crear las funciones apropiadas de comparación, igualdad y verdad en consecuencia.

    Tengo una clase lógica de 3 valores en mi módulo dbf .

    Implementa False / True / Unknown como valores singleton Falsth / Truth / Unknown . Implementa todos los operadores de comparación y también permite la comparación con los singletons de Python. False / True / None ( None significa “desconocido”). Cualquier comparación con un valor Unknown da como resultado Unknown , y un bash de usar implícitamente un valor Unknown en una sentencia if (u otro contexto bool ) Falsth un Falsth , aunque se pueden usar Truth y Falsth en contextos booleanos, y se puede comparar Unknown Contra directamente.

    Debido a que no es posible anular el comportamiento and , or , y not el tipo, anula los operadores a nivel de bits & , | , y ~ .

    También implementa __index__ con Unknown tiene el valor de 2 .

    Ejemplo:

     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." 

    No hay tales tipos incorporados. Y enumeración tampoco son compatibles como un tipo. Sin embargo, puedes usar constante como:

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

    No soy un progtwigdor de Python, pero podría devolver Ninguno en el caso No sé . La persona que llama tendría que verificar “Sí”, “No” o Ninguna, pero al menos sabrían que usted no sabe.

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

    Nunca vi un tipo similar al booleano que tenía más de dos valores. Después de todo, “booleano” significa que la función opera sobre “dominio booleano”, que a su vez tiene exactamente 2 valores.

    Dicho esto, es perfectamente correcto usar números enteros, enumeraciones o incluso cadenas. En Python, puede crear un módulo que contenga solo las variables SÍ, NO, MAYOR e importar desde allí a cualquier otro lugar.