Ralf M. wrote: > 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.
But that is exactly the right approach. Avoid importing the main script under its name because that will run all code that is not guarded by if __name__ == "__main__": ... twice. In your case it's enum, but the same goes for every class, function or object and the module itself. In Python they are all created rather than declared. > 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? mod2 could import the __main__ module, e. g. > ##### Code of mod2.py ##### import __main__ as mod1 > def getA(): > return mod1.En.A > ##### End of mod2.py ##### but that would hardcode the assumption that __main__ is always mod1.py. The only sane option is to not put anything in the main script that needs to be imported by other modules. > 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() -- https://mail.python.org/mailman/listinfo/python-list