There are issues. In most Python scripts, the issue isn't noticed much because the lifetime of Python itself is usually the same as the script. You would begin to notice if you ran Python interactively for a long session, doing multiple things within the same interactive session. This is further complicated by some of the Python packages are implemented in C/C++ ( and even Fortran ) such as NumPy. Python loads these as shared libraries, and there is no safe way to unload the shared library from a running process, other than a restart. JMP is in a similar position with the Python shared library itself, it can't be unloaded. Yes, del works to release objects. However, del sys isn't doing what you might expect. This isn't deleting or unloading the 'module' or unloading dependent dlls, it's simply deleting the 'sys' object that's holding the references to the loaded module. The other aspect is that sys is a Python built-in module, not the same as a loaded module. Further deleting 'sys' doesn't clean up any changes you may have made, for example appending another path to sys.path.
If you do:
sys.path.append('/usr/local/bin')
print(sys.path)
del sys
print(sys.path). # gives error on sys
import sys
print(sys.path). # still contains the /usr/local/bin addition
The above was run in an interactive session in a terminal window. Only exiting Python and restarting cleared the /usr/local/bin from sys.path. The only real way is for you to keep track of all the variables used in a session and then delete them at the end of the 'session'. One way would be to put each variable in a list, or dictionary, then delete the container at the end of the session.
I am researching the use of Python sub-interpreters which could allow setting up code that doesn't run in the global environment, the idea being the sub-interpreter is independent, and shutting down the sub-interpreter would act like a shut down and restart of Python. At present, I haven't found a way to safely shut down and restart the main Python interpreter within the lifetime of a JMP session.
The current Python practice to reload a module ( starting with Python 3.4) is
import importlib
importlib.reload(modulename)
Trying to reload sys gives
>>> importlib.reload(sys)
<module 'sys' (built-in)>
Reloading numpy, gives the following output...
>>> importlib.reload(np)
/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/importlib/__init__.py:169: UserWarning: The NumPy module was reloaded (imported a second time). This can in some cases result in small but subtle issues and is discouraged.
_bootstrap._exec(spec, module)
<module 'numpy' from '/Library/Frameworks/Python.framework/Versions/3.11/lib/python3.11/site-packages/numpy/__init__.py'>
Note the UserWarning:
UserWarning: The NumPy module was reloaded (imported a second time). This can in some cases result in small but subtle issues and is discouraged. _bootstrap._exec(spec, module)
Even with the 'official' way of reloading a module can cause issues.
importlib.reload() works great for when you are developing a Python module in code, since changes to the a module's source will not be reflected until a reload. Which potentially forces a recompile to .pyc of the Python code.