How to compare Enums in Python?
<p>Since Python 3.4, the <code>Enum</code> class exists.</p>

<p>I am writing a program, where some constants have a specific order and I wonder which way is the most pythonic to compare them:</p>

<pre><code>class Information(Enum):
    ValueOnly = 0
    FirstDerivative = 1
    SecondDerivative = 2
</code></pre>

<p>Now there is a method, which needs to compare a given <code>information</code> of <code>Information</code> with the different enums:</p>

<pre><code>information = Information.FirstDerivative
print(value)
if information &gt;= Information.FirstDerivative:
    print(jacobian)
if information &gt;= Information.SecondDerivative:
    print(hessian)
</code></pre>

<p>The direct comparison does not work with Enums, so there are three approaches and I wonder which one is preferred:</p>

<p>Approach 1: Use values:</p>

<pre><code>if information.value &gt;= Information.FirstDerivative.value:
     ...
</code></pre>

<p>Approach 2: Use IntEnum:</p>

<pre><code>class Information(IntEnum):
    ...
</code></pre>

<p>Approach 3: Not using Enums at all:</p>

<pre><code>class Information:
    ValueOnly = 0
    FirstDerivative = 1
    SecondDerivative = 2
</code></pre>

<p>Each approach works, Approach 1 is a bit more verbose, while Approach 2 uses the not recommended IntEnum-class, while  and Approach 3 seems to be the way one did this before Enum was added. </p>

<p>I tend to use Approach 1, but I am not sure. </p>

<p>Thanks for any advise!</p>

<p>You should always implement the rich comparison operaters if you want to use them with an <code>Enum</code>. Using the <code>functools.total_ordering</code> class decorator, you only need to implement an <code>__eq__</code> method along with a single ordering, e.g. <code>__lt__</code>. Since <code>enum.Enum</code> already implements <code>__eq__</code> this becomes even easier:</p>

<pre><code>&gt;&gt;&gt; import enum
&gt;&gt;&gt; from functools import total_ordering
&gt;&gt;&gt; @total_ordering
... class Grade(enum.Enum):
...   A = 5
...   B = 4
...   C = 3
...   D = 2
...   F = 1
...   def __lt__(self, other):
...     if self.__class__ is other.__class__:
...       return self.value &lt; other.value
...     return NotImplemented
... 
&gt;&gt;&gt; Grade.A &gt;= Grade.B
True
&gt;&gt;&gt; Grade.A &gt;= 3
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
TypeError: unorderable types: Grade() &gt;= int()
</code></pre>

<p>Terrible, horrible, ghastly things can happen with <code>IntEnum</code>. It was mostly included for backwards-compatibility sake, enums used to be implemented by subclassing <code>int</code>. From the <a href="https://docs.python.org/3/library/enum.html#intenum" rel="nofollow">docs</a>:</p>

<blockquote>
  <p>For the vast majority of code, Enum is strongly recommended, since
  IntEnum breaks some semantic promises of an enumeration (by being
  comparable to integers, and thus by transitivity to other unrelated
  enumerations). It should be used only in special cases where thereâs
  no other choice; for example, when integer constants are replaced with
  enumerations and backwards compatibility is required with code that
  still expects integers.</p>
</blockquote>

<p>Here's an example of why you don't want to do this:</p>

<pre><code>&gt;&gt;&gt; class GradeNum(enum.IntEnum):
...   A = 5
...   B = 4
...   C = 3
...   D = 2
...   F = 1
... 
&gt;&gt;&gt; class Suit(enum.IntEnum):
...   spade = 4
...   heart = 3
...   diamond = 2
...   club = 1
... 
&gt;&gt;&gt; GradeNum.A &gt;= GradeNum.B
True
&gt;&gt;&gt; GradeNum.A &gt;= 3
True
&gt;&gt;&gt; GradeNum.B == Suit.spade
True
&gt;&gt;&gt; 
</code></pre>

python enums compare