on perhaps unloading modules?

Greg Ewing greg.ewing at canterbury.ac.nz
Mon Aug 16 02:55:45 EDT 2021


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


More information about the Python-list mailing list