On 16/08/21 1:50 am, Hope Rouselle wrote:
By the way, I'm aware that what I'm doing here is totally unsafe and I could get my system destroyed. I'm not planning on using this --- thank you for your concern. I'm just interested in understanding more about modules.
Okay, I'll assume all the security issues have been taken are of, e.g. by running all of this in a virtual machine...
Notice how student m0 (who really scored a zero) first gets his grade right, but if I invoke it again, then it gets 50.0.
The best way to do this would be to run each student's file in a separate process, so you know you're getting a completely fresh start each time. The second best way would be to not use import_module, but to exec() the student's code. That way you don't create an entry in sys.modules and don't have to worry about somehow unloading the module. Something like code = read_student_file(student_name) env = {} # A dict to hold the student's module-level definitions exec(code, env) grade_question1(env) env['procedure_x'] = key.procedure_x grade_question2(env) ...etc...
That's not the whole problem. For reasons I don't understand, new modules I load --- that is, different students --- get mixed with these modifications in m0 that I made at some point in my code.
I would have to see a specific example of that. One thing to keep in mind is that if key.procedure_x modifies any globals in the key module, it will still modify globals in the key module -- not the student's module -- after being transplanted there. More generally, there are countless ways that a student's code could modify something outside of its own module and affect the behaviour of other student's code. This is why it would be vastly preferable to run each test in a fresh process.
(*) If it were easy to unload modules...
It's sometimes possible to unload and reimport a module, but only if the module's effects are completely self-contained. That depends not only on what the module itself does, but what other modules do with it. If any other module has imported it, that module will still contain references to the old module; if there are instances of a class defined in it still existing, they will still be instances of the old version of the class; etc. 99.999% of the time it's easier to just start again with a fresh Python process. -- Greg -- https://mail.python.org/mailman/listinfo/python-list