Enums are Singletons - but not always?

Terry Reedy tjreedy at udel.edu
Sat May 23 21:07:43 EDT 2020


On 5/23/2020 2:21 PM, Ralf M. wrote:

> ##### 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()

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

As a couple of people mentioned, the issue is the circular import.  When 
you run mod1 from a command line, its name is __main__.  Its execution 
of mod1 code stops to execute enum code and then mod2 code.

Execution of mod2 stops to execute mod1 code in a new module named 
'mod1'.  When the second execution of mod1 code does the import of enum 
and mod2, sys.modules['enum'] and sys.modules['mod2'] exist, are found, 
and used to satify the import.  So enum and mod2 code are not executed 
again.  In the 'mod1' module, 'mod2' is linked to the *incomplete* mod2. 
  This 'works' in your code because the reference to mod2 within def 
main is not used because the name is 'mod1', not '__main__'.  But if in 
mod1, you had written

import enum
from mod2 import getA

the second execution of mod1 would fail because mod2.getA does not exist 
because execution of mod2 is paused to import mod1

When the mod1 import in mod2 finishes, the execution of mod2 code for 
'mod2' finishes without issue.  Then the execution of 'mod1' code in 
'__main__' finishes with the call to main.

When you instead interactively import mod1, it is executed just once and 
you have to explicitly call main.

In idlelib, pyshell currently has the IDLE Shell code, the main() 
function, and a couple of classes used elsewhere.  (An atrocious design 
that I inherited and have only partly fixed.)  As a *temporary* fix to 
an issue due to there being  duplicate '__main__' and 'pyshell' modules, 
I added the following to the top of pyshell.

import sys
if __name__ == "__main__":
     sys.modules['idlelib.pyshell']=sys.modules['__main__']

But doing what others suggested, limiting the main or start module to 
one-time code, is better.


-- 
Terry Jan Reedy




More information about the Python-list mailing list