Sunday, December 23, 2018

Dynamic function creation at run time with Python's eval built-in

By Vasudev Ram



Hi, readers,

A few days ago, I had published this post:

Dynamic function creation at run time with Python's exec built-in

In today's post I'll show another way of dynamically creating functions at run time - this time using Python's eval built-in instead of exec.

I'll show the code (dyn_func_with_eval.py), followed by its output.
# dyn_func_with_eval.py 
# Purpose: To dynamically create (and run) a function at run time, 
# using Python's eval built-in.
# Author: Vasudev Ram
# Copyright 2018 Vasudev Ram
# Web site: https://vasudevram.github.io
# Product store: https://gumroad.com/vasudevram
# Twitter: https://twitter.com/vasudevram

from __future__ import print_function

expr = raw_input("Enter a function of x: ")
print("expr: ", expr)
g = eval("lambda x: " + expr)
print("g:", g)
print("g.func_code.co_argcount:", g.func_code.co_argcount)
print("g.func_code.co_varnames:", g.func_code.co_varnames)
print("g(0):", g(0))

old_gi = 0
for i in range(5):
    gi = g(i)
    diff = gi - old_gi
    print("i = {}, g({}) = {}, diff = {}".format(i, i, gi, diff))
    old_gi = gi
As you can see, after prefixing the expression (that was input by the user) with "lambda x: ", to make it a complete lambda function definition, the program uses eval() (instead of exec() like last time), to dynamically evaluate the entered expression (which should represent a function of x).

The end result is that the lambda function object is created and then bound to the name g. Then g is used in the remaining code.

The values of g and g(0) are printed.

Then, in a loop, g is evaluated for i ranging from 0 to 4. For each such value, i, g(i) and the difference between the old g(i) and the current one is printed. (No meaningful value can be given for the previous value of g(i) before g(0), so I used 0 arbitrarily; ignore that first difference).

Now, the output:
$ python dyn_func_with_eval.py
Enter a function of x: x * x + 2 * x + 1
expr:  x * x + 2 * x + 1
g: <function <lambda> at 0x022D0A70>
g.func_code.co_argcount: 1
g.func_code.co_varnames: ('x',)
g(0): 1
i = 0, g(0) = 1, diff = 1
i = 1, g(1) = 4, diff = 3
i = 2, g(2) = 9, diff = 5
i = 3, g(3) = 16, diff = 7
i = 4, g(4) = 25, diff = 9

Note that I used Python introspection to print the argument count and the local variable names of the generated function.

So, it worked. We could enter a function of x via the keyboard, use eval() to dynamically create a Python function that uses it, and evaluate that function for some range of values. Are there any uses of this technique, other than to show that it is possible, and interesting? Sure, I can think of at least one: a graphing calculator. We could have a GUI window with a pane that can draw graphics, such as curves in the 2D plane (using one of the Python GUI toolkits like wxPython or PyQt that support this), and then repeatedly prompt the user for a function of x, eval() it as above, then plot the values of x and y (= g(x)) for a range, in a loop, to draw a curve that represents the function entered.

Note: Use of exec and eval can be a security risk, so only use them in a trusted environment. The optional arguments globals and locals, which I did not use in these two posts, may be of use to control the environment in which they run, but user input is also important.

In fact, the graphing calculator could probably be done as a web app too, using some Python web framework, such as Flask, Bottle, Django or other (a lightweight one may be better here, or even plain CGI), and a web form with an HTML5 canvas and some JavaScript on the front-end. The user could enter the formula (some function of x) in a text box, submit it, the back-end Python app could eval() it to create the function, evaluate that function for a range of points like I did above, and send the list of (x, y) pairs to the browser, where the JavaScript could draw a curve representing those points, on the canvas.

Did you notice any pattern to the values of g(i)? The values are 1, 4, 9, 16, 25 - which are the squares of the integers 1 to 5. But the formula I entered for g was not x * x, rather, it was x * x + 2 * x + 1. Then why are squares shown in the output? Reply in the
comments if you get it, otherwise I will answer next time.

The image at the top of the post is from the Wikipedia page about lambda (the Greek letter) and is of the Greek alphabet on a black figure vessel. Check out the many meanings and uses of the symbol/letter lambda in various fields (see that Wikipedia page).

- Enjoy.


- Vasudev Ram - online Python training and consulting


I conduct online courses on Python programming, Unix / Linux commands and shell scripting and SQL programming and database design, with course material and personal coaching sessions.

The course details and testimonials are here.

Contact me for details of course content, terms and schedule.

Getting a new web site or blog, and want to help preserve the environment at the same time? Check out GreenGeeks.com web hosting.

Sell your digital products via DPD: Digital Publishing for Ebooks and Downloads.

Learning Linux? Hit the ground running with my vi quickstart tutorial. I wrote it at the request of two Windows system administrator friends who were given additional charge of some Unix systems. They later told me that it helped them to quickly start using vi to edit text files on Unix. Of course, vi/vim is one of the most ubiquitous text editors around, and works on most other common operating systems and on some uncommon ones too, so the knowledge of how to use it will carry over to those systems too.

Check out WP Engine, powerful WordPress hosting.

Creating online products for sale? Check out ConvertKit, email marketing for online creators.

Teachable: feature-packed course creation platform, with unlimited video, courses and students.

Posts about: Python * DLang * xtopdf

My ActiveState Code recipes

Follow me on:



No comments: