13

In python ,There is a reload method to reload an imported module , but is there a method to reload the currently running script without restarting it, this would be very helpful in debugging a script and changing the code live while the script is running. In visual basic I remember a similar functionality was called "apply code changes", but I need a similar functionality as a function call like "refresh()" which will apply the code changes instantly.

This would work smoothly when an independent function in the script is modified and we need to immediately apply the code change without restarting the script.

Inshort will:

reload(self) 

work?

3
  • How can you reload the current script while it's still running?
    – ForceBru
    Commented Apr 30, 2015 at 6:36
  • see the updates for example
    – stackit
    Commented Apr 30, 2015 at 6:37
  • 1
    @ForceBru thats the question , VB does allow to reload , does python have this feature?
    – stackit
    Commented Apr 30, 2015 at 6:41

7 Answers 7

2

reload(self) will not work, because reload() works on modules, not live instances of classes. What you want is some logic external to your main application, which checks whether it has to be reloaded. You have to think about what is needed to re-create your application state upon reload.

Some hints in this direction: Guido van Rossum wrote once this: xreload.py; it does a bit more than reload() You would need a loop, which checks for changes every x seconds and applies this.

Also have a look at livecoding which basically does this. EDIT: I mistook this project for something else (which I didn't find now), sorry.

perhaps this SO question will help you

2
  • how to use livecoding? no examples provided?
    – stackit
    Commented Apr 30, 2015 at 7:51
  • sorry, mistook this for something else. if I find something better, I will edit my answer again
    – knitti
    Commented Apr 30, 2015 at 8:38
1

Intro

reload is for imported modules. Documentation for reload advises against reloading __main__.

Reloading sys, __main__, builtins and other key modules is not recommended.

To achieve similar behavior on your script you will need to re-execute the script. This will - for normal scripts - also reset the the global state. I propose a solution.

NOTE

The solution I propose is very powerful and should only be used for code you trust. Automatically executing code from unknown sources can lead to a world of pain. Python is not a good environment for soapboxing unsafe code.

Solution

To programmatically execute a python script from another script you only need the built-in functions open, compile and exec.

Here is an example function that will re-execute the script it is in:

def refresh():
    with open(__file__) as fo:
        source_code = fo.read()
        byte_code = compile(source_code, __file__, "exec")
        exec(byte_code)

The above will in normal circumstances also re-set any global variables you might have. If you wish to keep these variables you should check weather or not those variables have already been set. This can be done with a try-except block covering NameError exceptions. But that can be tedious so I propose using a flag variable.

Here is an example using the flag variable:

in_main = __name__ == "__main__"
first_run = "flag" not in globals()

if in_main and first_run:
    flag = True
2
  • so what is the final code assuming we want to preserve the global state
    – stackit
    Commented Dec 16, 2020 at 8:49
  • @stackit - whatever variable you want to protect from being re-set can be set in a decision block as I demonstrated at the end - the flag variable is only set on the first run through and never after that.
    – medecau
    Commented Dec 18, 2020 at 4:35
0

Perhaps you mean something like this:

import pdb
import importlib
from os.path import basename

def function():
    print("hello world")

if __name__ == "__main__":
    # import this module, but not as __main__ so everything other than this
    # if statement is executed
    mainmodname = basename(__file__)[:-3]
    module = importlib.import_module(mainmodname)

    while True:
        # reload the module to check for changes
        importlib.reload(module)
        # update the globals of __main__ with the any new or changed 
        # functions or classes in the reloaded module
        globals().update(vars(module))
        function()
        pdb.set_trace()

Run the code, then change the contents of function and enter c at the prompt to run the next iteration of the loop.

1
  • I dont want it just for debugging.
    – stackit
    Commented Apr 30, 2015 at 8:14
0

test.py

class Test(object):

    def getTest(self):
       return 'test1'

testReload.py

from test import Test
t = Test()
print t.getTest()

# change return value (test.py)

import importlib
module = importlib.import_module(Test.__module__)
reload(module)
from test import Test
t = Test()
print t.getTest()
1
  • 1
    Is this auto generated code? to gain rep points? Is this a bot?
    – stackit
    Commented Apr 15, 2016 at 13:00
0

None of these answers did the job properly for me, so I put together something very messy and very non-pythonic to do the job myself. Even after running it for several weeks, I am finding small issues and fixing them. One issue will be if your PWD/CWD changes.

Warning this is very ugly code. Perhaps someone will make it pretty, but it does work.

Not only does it create a refresh() function that properly reloads your script in a manner such that any Exceptions will properly display, but it creates refresh_<scriptname> functions for previously loaded scripts just-in-case you need to reload those.

Next I would probably add a require portion, so that scripts can reload other scripts -- but I'm not trying to make node.js here.

First, the "one-liner" that you need to insert in any script you want to refresh.

with open(os.path.dirname(__file__) + os.sep + 'refresh.py', 'r') as f:    \
    exec(compile(f.read().replace('__BASE__',                              \
        os.path.basename(__file__).replace('.py', '')).replace('__FILE__', \
            __file__), __file__, 'exec'))

And second, the actual refresh function which should be saved to refresh.py in the same directory. (See, room for improvement already).

def refresh(filepath = __file__, _globals = None, _locals = None):
    print("Reading {}...".format(filepath))
    if _globals is None:
        _globals = globals()
    _globals.update({
        "__file__": filepath,
        "__name__": "__main__",
    })
    with open(filepath, 'rb') as file:
        exec(compile(file.read(), filepath, 'exec'), _globals, _locals)

def refresh___BASE__():
    refresh("__FILE__")

Tested with Python 2.7 and 3.

0

Take a look at reload. You just need to install the plugin an use reload ./myscript.py, voilà

-1

If you are running in an interactive session you could use ipython autoreload

autoreload reloads modules automatically before entering the execution of code typed at the IPython prompt.

Of course this also works on module level, so you would do something like:

>>>import myscript
>>>myscript.main()
*do some changes in myscript.py*
>>>myscript.main() #is now changed
3
  • @stackit ipython is an python shell, so it is python. But the same works with the default python shell, pack your script into a module and then instead of python myscript do python; import myscript; myscript.main(); myscript = reload(myscript). Ipython just automates that for you with autoreload.
    – syntonym
    Commented Apr 30, 2015 at 6:54
  • but i need to do refreshing \apply code changes in a function call which is executed in response to file change events.
    – stackit
    Commented Apr 30, 2015 at 7:03
  • @stackit You should still be able to do that. Does it not work? What happens?
    – syntonym
    Commented Apr 30, 2015 at 13:33

Not the answer you're looking for? Browse other questions tagged or ask your own question.