osdir.com


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Enums are Singletons - but not always?


Hello,

recently I wrote a small library that uses an Enum. That worked as 
expected. Then I added a main() and if __name__ == "__main__" to make it 
runable as script. Now Enum members that should be the same aren't 
identical any more, there seem to be two instances of the same Enum.

I think I know what's going on, but cannot find a good and elegant way 
to avoid the problem. I hope someone here can help me there.

Below are a simplified code sample, the results when I run it and my 
thoughts.

##### Code of mod1.py #####
import enum, mod2
class En(enum.Enum):
     A = 1
     B = 2
def main():
     a = mod2.getA()
     print("a is En.A:", a is En.A)
     print("a:", repr(a), "    En.A:", repr(En.A))
     print("id(a), id(a.__class__)", id(a), id(a.__class__))
     print("id(En.A), id(En)      ", id(En.A), id(En))
if __name__ == "__main__":
     main()
##### End of mod1.py #####

##### Code of mod2.py #####
import mod1
def getA():
     return mod1.En.A
##### End of mod2.py #####

##### Results when run: #####
C:\tmp>py mod1.py
a is En.A: False
a: <En.A: 1>     En.A: <En.A: 1>
id(a), id(a.__class__) 33305864 7182808
id(En.A), id(En)       33180552 7183752

C:\tmp>py
Python 3.7.4 (tags/v3.7.4:e09359112e, Jul  8 2019, 20:34:20) [MSC v.1916 
64 bit
(AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
 >>> import mod1
 >>> mod1.main()
a is En.A: True
a: <En.A: 1>     En.A: <En.A: 1>
id(a), id(a.__class__) 49566792 44574280
id(En.A), id(En)       49566792 44574280
 >>>

So: When run as script there are two instances of En (different ids), 
but when mod1 is imported and mod1.main() is run it works as expected 
(just one instance of En, same ids).
BTW: py -m mod1 doesn't work either.

What I thing is happening:
When the script is run, mod1.py is executed and an instance of En and 
its members is created. During the same run mod1 is also imported (via 
mod2), the file mod1.py is executed again as part of the import and 
another, different instance of En and its members is created.

How do I have to change mod1.py to avoid the problem?
Currently I have moved main() into a new file script.py. That works, but 
is not what I wanted.

I doubt it's a bug in the enum module, but should that be the case, I'm 
willing to open an issue on the bug tracker.

Or can nothing be done about it?

Looking forward to any ideas
Ralf M.

P.S.:
As I was about to send this post the following modification occured to 
me (see below). It works, but it doesn't feel right to import a module 
directly from inside itself.
##### Modified code of mod1.py (one line added) #####
import enum, mod2
class En(enum.Enum):
     A = 1
     B = 2
from mod1 import En  # NEW LINE, overwrite just defined En
def main():
     a = mod2.getA()
     print("a is En.A:", a is En.A)
     print("a:", repr(a), "    En.A:", repr(En.A))
     print("id(a), id(a.__class__)", id(a), id(a.__class__))
     print("id(En.A), id(En)      ", id(En.A), id(En))
if __name__ == "__main__":
     main()