2

I quite like the incremental programming I can do in Smalltalk. You have a running program and you add to it as you flesh out your program. You can change methods and restart the stack with the changes applied to see what the new version does. While your program is running, you can inspect local state and change them.

Is something similar possible in Python? I have seen hints of such abilities, such as reload(), but I don't know enough about Python to understand exactly how its used. I have looked through some beginner Python books, but I didn't see any mention of this.

Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
maou
  • 185
  • 6
  • Do you mean running it in the interactive interpreter? Or use the `reload` function to reload a module? Both are options achieving what you want. – UnholySheep Dec 18 '18 at 18:53
  • Though considering that Python is interpreted and reasonably fast it's usually easier to just restart the entire applications instead of messing with modifying code while it's running – UnholySheep Dec 18 '18 at 18:55
  • 2
    I think many of the features you describe are due to Smalltalk being “image based”. There are some hints about it in this question’s answers: [Which programming languages (besides Smalltalk) are image based?](https://stackoverflow.com/questions/722204/which-programming-languages-besides-smalltalk-are-image-based). I am very curious for the answers to your question. – MartinW Dec 18 '18 at 20:00
  • 2
    I would distinguish between _possible_ and _natural_. A program in Smalltalk is an _extension_ of the environment/image, not a product built with it. This is why these features are natural, not just possible. – Leandro Caniglia Dec 18 '18 at 20:49
  • 1
    While it's not Python-related, I note that the Flutter mobile development platform features "stateful hot reload" as a major feature, in a language (Dart) less naturally friendly to it than any of these. So it's just a matter of doing it and making it natural. http://flutter.io – Alan Knight Dec 19 '18 at 19:06

4 Answers4

5

Some things won't be possible no matter what effort is put on Python. For example, while developing a web app, the Flask/Django/Gunicorn or whatnot webserver has to restart its process after a change in the sources. But in say Lisp, you start a web server in the REPL, and you just compile a function that for example adds a new route, and you can try it right away. No process was restarted, it's all more interactive.

Another example is updating classes and instances. In Common Lisp, suppose you wrote a class and created some objects. Now you change the class definition, and the existing instances get (lazily) updated. For instance, a new slot is added, one is removed, etc. And we can even control how the update is done (by subclassing some generic functions).

Attaching to a running and distant process in Python is doable, but the interactivity is much less, and the editing experience is also less ideal (a dumb python shell in the terminal by default VS a full blown Emacs where you can navigate the sources and re-compile functions in one keystroke (C-c C-c in Slime) (or in any other editor that can connect to a Swank server)).

Running one given unit test is also straightforward and fast, there is no process to restart.

References:

Ehvince
  • 17,274
  • 7
  • 58
  • 79
3

You can change function definitions on the fly.

E.g., you have a function mymodule.myfunc(x,y) and you want to see how it is called by long_process().

You do (at the REPL >>> prompt or in a notebook)

myfunc_orig = mymodule.myfunc
def myfunc_new(x,y):
    print("myfunc_new",x,y)
    return myfunc_orig(x,y)

mymodule.myfunc = myfunc_new

long_process()

Now you will get a printout every time mymodule.myfunc is called.

When you are done, you restore it with

mymodule.myfunc = myfunc_orig
sds
  • 58,617
  • 29
  • 161
  • 278
3

I use ipython for interactive mode - and either leave the terminal open until programming project is finished, or you can save the session by dill (in ipython console do: !pip install dill).

save session using dill package

To save all global variables and definitions do:

import dill       
dill.dump_session('.session.pkl')

Which in a new session you can load by:

import dill
dill.load_session('.session.pkl')

It is taken from here

Gwang-Jin Kim
  • 9,303
  • 17
  • 30
0

The built-in method exec(source_code, globals, locals) accepts the 'globals' and 'locals' arguments. These are very close to the execution 'environment', or 'execution image' from smalltalk.

A class/function/variable declared is added to globals/locals on returning from exec(..) call.

the globals/locals could easily be stored to a file and used as starting environment for future execution :)

That simulates the smalltalk 'image based'.

I imagine this trick can reproduce properties of smalltalk execution environment, is that true?

Example:

locals, globals = {}, {}
exec("""def f(x): return x+1""", globals, locals)
print(locals["f"](2))

exec("""def f(x): return x+10""", globals, locals)
print(locals["f"](2))
lenz
  • 5,658
  • 5
  • 24
  • 44