What's the best way to implement an 'enum' in Python?
In Python I'd do that with a wrapper object that holds one of those three values; I'd use
None. Since the implicit truthiness value of a Boolean-like object with three possible values is problematic, we'll solve that by disallowing that entirely (raising an exception in
__nonzero__(), or in Python 3,
__bool__()), thus requiring that comparisons always be done explicitly, using
!=. We'll implement equality as identity so that only the specific singleton values
None are matched.
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 objects, you must explicitly specify which values to match, i.e.
foo == True or bar != None. You can also do
foo in (False, None) to match multiple values (though of course
in two values is the opposite of
!= with a single value). If there are other logic operations you wish to be able to perform with these objects, you could implement these as methods, or possibly by overriding certain operators (sadly, however, logical
or are not overrideable, though there's a proposal to add that).
Also note that you can't override
id() in Python, so e.g.
Tristate(None) is None is
False; the two objects are in fact different. Since good Python style is to use
is when comparing against singletons, this is unfortunate, but unavoidable.
Edit 4/27/16: Added support for comparing one
Tristate object to another.