Prevent Python from caching the imported modules

后端 未结 8 1686
误落风尘
误落风尘 2020-11-28 07:40

While developing a largeish project (split in several files and folders) in Python with IPython, I run into the trouble of cached imported modules.

The problem is th

相关标签:
8条回答
  • 2020-11-28 08:10

    import checks to see if the module is in sys.modules, and if it is, it returns it. If you want import to load the module fresh from disk, you can delete the appropriate key in sys.modules first.

    There is the reload builtin function which will, given a module object, reload it from disk and that will get placed in sys.modules. Edit -- actually, it will recompile the code from the file on the disk, and then re-evalute it in the existing module's __dict__. Something potentially very different than making a new module object.

    Mike Graham is right though; getting reloading right if you have even a few live objects that reference the contents of the module you don't want anymore is hard. Existing objects will still reference the classes they were instantiated from is an obvious issue, but also all references created by means of from module import symbol will still point to whatever object from the old version of the module. Many subtly wrong things are possible.

    Edit: I agree with the consensus that restarting the interpreter is by far the most reliable thing. But for debugging purposes, I guess you could try something like the following. I'm certain that there are corner cases for which this wouldn't work, but if you aren't doing anything too crazy (otherwise) with module loading in your package, it might be useful.

    def reload_package(root_module):
        package_name = root_module.__name__
    
        # get a reference to each loaded module
        loaded_package_modules = dict([
            (key, value) for key, value in sys.modules.items() 
            if key.startswith(package_name) and isinstance(value, types.ModuleType)])
    
        # delete references to these loaded modules from sys.modules
        for key in loaded_package_modules:
            del sys.modules[key]
    
        # load each of the modules again; 
        # make old modules share state with new modules
        for key in loaded_package_modules:
            print 'loading %s' % key
            newmodule = __import__(key)
            oldmodule = loaded_package_modules[key]
            oldmodule.__dict__.clear()
            oldmodule.__dict__.update(newmodule.__dict__)
    

    Which I very briefly tested like so:

    import email, email.mime, email.mime.application
    reload_package(email)
    

    printing:

    reloading email.iterators
    reloading email.mime
    reloading email.quoprimime
    reloading email.encoders
    reloading email.errors
    reloading email
    reloading email.charset
    reloading email.mime.application
    reloading email._parseaddr
    reloading email.utils
    reloading email.mime.base
    reloading email.message
    reloading email.mime.nonmultipart
    reloading email.base64mime
    
    0 讨论(0)
  • 2020-11-28 08:10

    I am using PythonNet in my project. Fortunately, I found there is a command which can perfectly solve this problem.

    using (Py.GIL())
            {
                dynamic mod = Py.Import(this.moduleName);
                if (mod == null)
                    throw new Exception( string.Format("Cannot find module {0}. Python script may not be complied successfully or module name is illegal.", this.moduleName));
    
                // This command works perfect for me!
                PythonEngine.ReloadModule(mod);
    
                dynamic instance = mod.ClassName();
    
    0 讨论(0)
提交回复
热议问题