RussAbbott
RussAbbott

Reputation: 2738

Python program bombs out after finishing

I'm getting a strange Python error. I'm executing a file that looks like this.

if __name__ == '__main__':
    MyClass().main()
    print('Done 1')
    print('Done 2')

The preceding runs successfully. But when I change it to this, I get the strange result.

if __name__ == '__main__':
    myObject = MyClass()
    myObject.main()
    print('Done 1')
    print('Done 2')

The output looks like this.

Done 1
Done 2
Exception ignored in: <function Viewer.__del__ at 0x0000021569EF72F0> 
Traceback (most recent call last):
  File "C:\...\lib\site-packages\gym\envs\classic_control\rendering.py", line 143, in __del__
  File "C:\...\lib\site-packages\gym\envs\classic_control\rendering.py", line 62, in close
  File "C:\...\lib\site-packages\pyglet\window\win32\__init__.py", line 305, in close
  File "C:\...\lib\site-packages\pyglet\window\__init__.py", line 770, in close
ImportError: sys.meta_path is None, Python is likely shutting down

Process finished with exit code 0

There is a blank line after the final print line. The same thing happens when the final line does not have an end-of-line marker.

I get the same result whether I run it from within PyCharm using the run command or from the terminal.

As you can probably tell from the error lines, the program generates an animation. (It's the cart-pole problem from OpenAI gym.)

Since the program completes before the error, it's not a disaster. But I'd like to understand what's happening.

Thanks.

Upvotes: 1

Views: 1098

Answers (1)

jedwards
jedwards

Reputation: 30210

Python provides a __del__ dunder method for classes that will be called as the instances are garbage collected, if they're garbage collected.

When it's used, the __del__ method typically performs some sort of cleanup.

Due to the fact that it's fairly easy to inadvertently prevent an object from being collected, reliance on the __del__ to perform cleanup (instead of say, a context manager's __exit__ or an explicit .close() method) is generally advised against.

Your error highlights a different reason for avoiding relying on __del__, however: that during shutdown __del__ will be called but possibly after other things that it relies on are freed.

The proposed workarounds on the github issue linked in the comments should be instructive, as they all ensure that the cleanup is done at a time where the things that that cleanup relies on (e.g. sys.meta_path) are still in defined/not yet freed, e.g.:

try:
    del env
except ImportError:
    pass

and

env = gym.make('CartPole-v0')
...
env.env.close()

and (likely, but much less efficient or clear)

import gc; gc.collect()

Upvotes: 2

Related Questions