This evaluates expressions and displays their results as you type them. It's like some hack I posted a year ago, except that it doesn't look quite as ugly and it has noticeably better updating behavior. Still, it doesn't limit the time to evaluate an expression, and doesn't effectively let you define functions.
This is yet another a prototype for the "functional programming for amateurs in an outliner" goal. #!/usr/bin/python """Functional outline -- at least, eventually. No outlining yet. This is "one to throw away." To do: D bring up a window D add an exit button D add "add row" button D make its focus behavior sensible D fix shitty colors - remove "select all on focus" behavior - make entry fields' "relief" change on focus? No relief for now. - fix packing - remove empty rows? Rearrange rows? Gravy... - build f2c D add f D add c (in Python), and value - add re-evaluation D store all definitions in one object D start by recalculating everything in dumb order on any change, then... - topologically sort - use compile(expr, varname, 'eval').co_names to find dependencies. Maybe display them? - add "valid" bit. - Before setting new value, set to invalid; propagate this to dependents. - after setting new value, set to valid. - For display, maybe get new value for everything invalid that wants display - add K - add f2c - add hierarchy --- expand/collapse - add ability to *call* f2c - build something recursive - how about factorial? - add persistence """ import Tkinter, sys bgcolor='white' mainwin = Tkinter.Tk() mainwin.title('quickfunc') mainwin['background'] = bgcolor varrows = Tkinter.Frame(mainwin, background=bgcolor) varrows.pack(side='top') def leftwidget(parent, ctor=Tkinter.Entry, **args): rv = ctor(parent, background=bgcolor, **args) rv.pack(side='left', fill='both') return rv class namespace: def __init__(self): self.variables = [] self.values = {} self.exceptions = {} def add_var(self, namevar, exprvar, value_widget): self.variables.append((namevar, exprvar, value_widget)) def recalculate_everything(self, *stupid_tcl_vars): self.values.clear() for namevar, exprvar, widget in self.variables: name = namevar.get() try: value = eval(exprvar.get(), self.values) self.values[name] = value widget['text'] = repr(value) widget['background'] = bgcolor except: self.exceptions[name] = sys.exc_info() widget['background'] = 'red' def row(name, expr, env): f = Tkinter.Frame(varrows, background=bgcolor) f.pack(fill='both') fnamevar = Tkinter.Variable() fnamevar.set(name) fname = leftwidget(f, relief='flat', textvariable=fnamevar, width=8, justify='right', highlightthickness=0) equal = leftwidget(f, Tkinter.Label, text=':') exprvar = Tkinter.Variable() fexpr = leftwidget(f, relief='flat', textvariable=exprvar, highlightthickness=0) fvalue = leftwidget(f, Tkinter.Label) env.add_var(namevar=fnamevar, exprvar=exprvar, value_widget=fvalue) exprvar.trace('w', env.recalculate_everything) fnamevar.trace('w', env.recalculate_everything) exprvar.set(expr) fexpr.focus() return f env = namespace() f = row('f', '212', env) c = row('c', '(f - 32) * 5 / 9', env) def addrow_cmd(): row('', '', env) addrow = Tkinter.Button(mainwin, text="New row", command=addrow_cmd) addrow.pack(side='left') exit = Tkinter.Button(mainwin, text="Exit", command=mainwin.quit) exit.pack(side='left') Tkinter.mainloop()