Absolutely not, unfortunately. One of the architectural issues plaguing even comparatively memory-safe languages is the fact that there is a global scope that's accessible from anywhere. In some Python versions even numbers or truth values could be redefined. [0]
This makes it impossible to sandbox functions or imported modules, because they can communicate arbitrarily. But communication/access security is not the only problem. Resource security is something I haven't seen any significant language (besides Java perhaps) try to approach - being able to limit the memory and cpu usage of a (part of a) program. Modern languages should make it possible to do both with just a few lines of code.
I recommend reading about Capability Security[1], the E language[2] and the Principle of least Authority (POLA) [3]
These originated in the mainframe era, in a connected world before the internet, at the inception of the first multi-user systems: https://github.com/void4/notes/issues/41
CPython is not even memory-safe. The compiled bytecode is accessible to ordinary Python code able to replace it with 'incorrect' bytecode that causes out-of-bounds memory access by the C interpreter.
(Presumably an unusual thing to do -- I've seen libraries doing bytecode hacks but I'm not sure how popular any of them are.)
The compiled byte code in the file system is accessible and reversible, yes. But not once the interpreter has imported it.
A subsequent import could patch the Python object namespace, but that’s normal and intended.
If a program has access to the byte code files, it presumable has access to the actual .py files, and can easily change them to do whatever mayhem it wants.
There is no issue with just limiting resources (unless there is unpredictable overhead). It doesn't have to be hardware resources either, it could be abstract/higher level resources like interpreter steps or managed memory slices.
I'm creating a series of VMs to show that this is possible, like rarVM, the recursively sandboxable virtual machine: https://esolangs.org/wiki/RarVM
When calling a function you can specify how many interpreter steps it can run until it aborts (and optionally gives you a continuation so you can "refill" and resume it later).
Stackless Python can do this too, but unfortunately due to the reasons discussed above will never be a safe language, also this specific mechanism works only in trusted environments since the called function has the ambient authority to increase its own resource limits: https://stackless.readthedocs.io/en/2.7-slp/library/stackles...
This makes it impossible to sandbox functions or imported modules, because they can communicate arbitrarily. But communication/access security is not the only problem. Resource security is something I haven't seen any significant language (besides Java perhaps) try to approach - being able to limit the memory and cpu usage of a (part of a) program. Modern languages should make it possible to do both with just a few lines of code.
I recommend reading about Capability Security[1], the E language[2] and the Principle of least Authority (POLA) [3]
[0] https://hforsten.com/redefining-the-number-2-in-python.html
[1] http://www.cap-lore.com/CapTheory/
https://en.m.wikipedia.org/wiki/Capability-based_security
[2] http://www.erights.org/
[3] https://medium.com/agoric/pola-would-have-prevented-the-even...
These originated in the mainframe era, in a connected world before the internet, at the inception of the first multi-user systems: https://github.com/void4/notes/issues/41