1

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.

RussAbbott
  • 2,660
  • 4
  • 24
  • 37
  • Try to add `env.close()` to your code, for more details see: https://github.com/openai/gym/issues/893#issuecomment-369519156 – Nir Alfasi Oct 30 '18 at 03:45
  • does adding `import gc; gc.collect()` after the print statements prevent the output? – jedwards Oct 30 '18 at 03:45
  • 2
    Can you provide the code for MyClass or a minimum case which reproduces this bug - https://stackoverflow.com/help/mcve ? – arunkumar Oct 30 '18 at 03:52
  • 1
    @alfasin. Adding `env.close()` as the last line in `main` solved the problem. Thanks. Interestingly, the cart-pole environment terminates an episode only when the cart or pole go out of bounds. Otherwise one can `step` forever. So if the program that calls `env.step()` terminates the episode after some number of steps, the environment is left hanging in what it thinks is the middle of an episode. – RussAbbott Oct 30 '18 at 03:58

1 Answers1

2

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()
jedwards
  • 29,432
  • 3
  • 65
  • 92
  • Thanks for the explanation. For those interested in why it came up in this context, please also see my comment on the original question. – RussAbbott Oct 30 '18 at 15:54