Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Imported Enum class is not comparing equal to itself

In my code, I was puzzled by Enum instances with the same value not comparing equal. I quickly realized that their id(...) were different. Later, much less quickly, I realized that the only change since it last worked was the import statement: using explicit module path rather than relative.

Then I came up with this isolated example.

$ ls
e/

$ ls e
__init__.py  __pycache__/  m1.py  m1.pyc  m2.py

$  python3 --version
Python 3.5.1

$ cat e/m1.py
from enum import Enum
class E(Enum):
    x=0

$ cat e/m2.py
from m1 import E as E1
from e.m1 import E as E2

print(id(E1), id(E1.x))
print(id(E2), id(E2.x))

Let's run it:

$ PYTHONPATH=~/test python3 e/m2.py
41536520 42656096
41537464 42656488

Obviously, equality (which is by identity for Enum) does not hold. Anyone else out there find this troubling?

Let me elaborate. Adding two more files:

$ cat e/file1.py
from m1 import E

class C():
    def __init__(self):
        self.x = E.x

One more. Note the difference in imports.

$ cat e/file2.py
from e.m1 import E
from file1 import C

c = C()
print(c.x, E.x)
print('Surprise! ->', c.x is E.x)

Both are valid imports. Now run it.

$ PYTHONPATH=~/test python3 e/file2.py
E.x E.x
Surprise! -> False

How can I avoid this trap? Is there a reason why I should not be troubled by this?

like image 361
user443854 Avatar asked Nov 02 '16 01:11

user443854


People also ask

Can == be used on enum?

equals method uses == operator internally to check if two enum are equal. This means, You can compare Enum using both == and equals method.

Can enum have two same values python?

Introduction to the enum aliases By definition, the enumeration member values are unique. However, you can create different member names with the same values.

What is the difference between enum and constant in Java?

The only difference is that enum constants are public , static and final (unchangeable - cannot be overridden). An enum cannot be used to create objects, and it cannot extend other classes (but it can implement interfaces).


2 Answers

Later, much less quickly, I realized that the only change since it last worked was the import statement: using explicit module path rather than relative.

Python 3 doesn't have implicit relative imports. Your "relative" import is actually another absolute import. You're importing two completely distinct modules, m1 and e.m1, that happen to come from the same file.

If you want to use a relative import in Python 3, you need to make it explicit:

from .m1 import E
#    ^ explicit relative import

If you run the program as

python3 -m e.m2

you'll avoid the problems with the module search path that allowed both m1 and e.m1 to exist. You can also manually fix sys.path and set __package__ from e/m2.py.

like image 151
user2357112 supports Monica Avatar answered Sep 20 '22 02:09

user2357112 supports Monica


This is not an issue with Enum, but with python imports. If you import the same module with a different name, you get two different modules.

Try, for example, E1 is E2.

like image 40
Ethan Furman Avatar answered Sep 19 '22 02:09

Ethan Furman