Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to isolate enums by making a distinction on type?

The following code defines two enums

class Insect:
    BEE = 0x00
    WASP = 0x01
    BUMBLEBEE = 0x02


class Breakfast:
    HAM = 0x00
    EGGS = 0x01
    PANCAKES = 0x02


b = Insect.WASP
if b == Breakfast.EGGS:
    print("ok")

As the condition illustrates, one is left open to make a mistake of testing against an entirely distinct enum. How can I isolate the enums, by type not by distinct values, so that the test above will generate an error?

Update

I see that this is one of the finer points along the road of moving from Python 2 to Python 3.

Thanks to wim's suggestion, the following code will generate an error if I attempt to compare apples and oranges.

from enum import Enum


class Apple(Enum):
    RED_DELICIOUS = 0x00
    GALA = 0x01
    FUJI = 0x02

    def __eq__(self, other):
        if type(other) is not type(self):
            raise Exception("You can't compare apples and oranges.")
        return super().__eq__(other)


class Orange(Enum):
    NAVEL = 0x00
    BLOOD = 0x01
    VALENCIA = 0x02

    def __eq__(self, other):
        if type(other) is not type(self):
            raise Exception("You can't compare apples and oranges.")
        return super().__eq__(other)


apple = Apple.GALA
if apple == Orange.BLOOD:
    print("ok")
like image 364
Calaf Avatar asked Dec 24 '22 09:12

Calaf


2 Answers

Don't use a custom class for it. Use the stdlib's enum type, they'll do the right thing here.

from enum import Enum

class Insect(Enum):
    ...

If you want a hard crash:

class MyEnum(Enum):

    def __eq__(self, other):
        if type(other) is not type(self):
            raise Exception("Don't do that")
        return super().__eq__(other)

But I caution against this design, since:

  1. enum instances are often compared by identity and not equality
  2. there is little (no?) precedent in Python for equality comparisons raising errors
like image 137
wim Avatar answered Jan 09 '23 04:01

wim


A few notes on equality testing, why it shouldn't raise exceptions, and proper type testing.

Why shouldn't == raise exceptions?

Equality testing is used constantly throughout Python, especially in containers: list, dict, and set, to name a few, rely on equality testing to find members, return members, change members, remove members, etc. If your Apple Enum raises every time it is compared to a non-Apple it will break any container it is added to.

Correct way for custom types to fail equality tests (and other comparison tests)

def __eq__(self, other):
    if not isinstance(other, self.__class__):
        return NotImplented   # note:  NOT RAISE
    ... comparison here ...

NB. The above tests are already built in to the Enum type.

Proper type testing

If you really, really want to ensure you don't get a type you don't want, and an error should be the result:

var1 = ...
if not isinstance(var1, SomeTypeHere):
    raise SomeException

But the above code SHOULD NOT be in any rich comparison method*.


*The rich comparison methods are __eq__, __ne__, __ge__, __gt__, __le__, and __lt__.

like image 33
Ethan Furman Avatar answered Jan 09 '23 05:01

Ethan Furman