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