This chapter is taken from the book A Primer on Scientific Programming with Python by H. P. Langtangen, 5th edition, Springer, 2016.

It is possible to provide text with valid Python code as input to a program and then turn the text into live objects as if the text were written directly into the program beforehand. This is a very powerful tool for letting users specify function formulas, for instance, as input to a program. The program code itself has no knowledge about the kind of function the user wants to work with, yet at run time the user's desired formula enters the computations.

The `eval`

functions takes a string as argument and
evaluates this string as a Python *expression*. The result of an
expression is an object. Consider

```
>>> r = eval('1+2')
>>> r
3
>>> type(r)
<type 'int'>
```

The result of `r = eval('1+2')`

is the same as if we had written
`r = 1+2`

directly:

```
>>> r = 1+2
>>> r
3
>>> type(r)
<type 'int'>
```

In general, any valid Python expression stored as text in a string `s`

can be turned into live Python code by `eval(s)`

.
Here is an example where the string to be evaluated is `'2.5'`

, which
causes Python to see `r = 2.5`

and make a `float`

object:

```
>>> r = eval('2.5')
>>> r
2.5
>>> type(r)
<type 'float'>
```

Let us proceed with some more examples. We can put the initialization of
a list inside quotes and use `eval`

to make a `list`

object:

```
>>> r = eval('[1, 6, 7.5]')
>>> r
[1, 6, 7.5]
>>> type(r)
<type 'list'>
```

Again, the assignment to `r`

is equivalent to writing

```
>>> r = [1, 6, 7.5]
```

We can also make a `tuple`

object by using tuple syntax (standard
parentheses instead of brackets):

```
>>> r = eval('(-1, 1)')
>>> r
(-1, 1)
>>> type(r)
<type 'tuple'>
```

Another example reads

```
>>> from math import sqrt
>>> r = eval('sqrt(2)')
>>> r
1.4142135623730951
>>> type(r)
<type 'float'>
```

At the time we run `eval('sqrt(2)')`

, this is the same as if we had
written

```
>>> r = sqrt(2)
```

directly, and this is valid syntax only if the `sqrt`

function is defined.
Therefore, the import of `sqrt`

prior to running `eval`

is
important in this example.
If we put a string, enclosed in quotes, inside the expression string, the result is a string object:

```
>>>
>>> r = eval('"math programming"')
>>> r
'math programming'
>>> type(r)
<type 'str'>
```

Note that we must use two types of quotes: first double quotes to mark
`math programming`

as a string object and then another set of quotes,
here single quotes (but we could also have used triple single quotes),
to embed the text `"math programming"`

inside a string. It does not
matter if we have single or double quotes as inner or outer quotes,
i.e., `'"..."'`

is the same as `"'...'"`

, because `'`

and `"`

are
interchangeable as long as a pair of either type is used consistently.
Writing just

```
>>> r = eval('math programming')
```

is the same as writing

```
>>> r = math programming
```

which is an invalid expression. Python will in this case think that
`math`

and `programming`

are two (undefined) variables, and setting two
variables next to each other with a space in between is invalid Python
syntax. However,

```
>>> r = 'math programming'
```

is valid syntax, as this is how we initialize a string `r`

in Python.
To repeat,
if we put the valid syntax `'math programming'`

inside a string,

```
s = "'math programming'"
```

`eval(s)`

will evaluate the text inside the double quotes as
`'math programming'`

, which yields a string.
So, why is the `eval`

function so useful? When we get input via
`raw_input`

or `sys.argv`

, it is always in the form of a string
object, which often must be converted to another type of object,
usually an `int`

or `float`

. Sometimes we want to avoid specifying
one particular type. The `eval`

function can then be of help: we feed
the string object from the input to the `eval`

function and let the it
interpret the string and convert it to the right object.

An example may clarify the point. Consider a small program where we
read in two values and add them. The values could be strings, floats,
integers, lists, and so forth, as long as we can apply a `+`

operator
to the values. Since we do not know if the user supplies a string,
float, integer, or something else, we just convert the input by
`eval`

, which means that the user's syntax will determine the type.
The program goes as follows
(`add_input.py`):

```
i1 = eval(raw_input('Give input: '))
i2 = eval(raw_input('Give input: '))
r = i1 + i2
print '%s + %s becomes %s\nwith value %s' % \
(type(i1), type(i2), type(r), r)
```

Observe that we write out the two supplied values,
together with the types of the values (obtained by `eval`

), and the sum.
Let us run the program with
an integer and a real number as input:

```
add_input.py
Give input: 4
Give input: 3.1
<type 'int'> + <type 'float'> becomes <type 'float'>
with value 7.1
```

The string `'4'`

, returned by the first call to `raw_input`

,
is interpreted as an `int`

by `eval`

, while `'3.1'`

gives
rise to a `float`

object.
Supplying two lists also works fine:

```
add_input.py
Give input: [-1, 3.2]
Give input: [9,-2,0,0]
<type 'list'> + <type 'list'> becomes <type 'list'>
with value [-1, 3.2000000000000002, 9, -2, 0, 0]
```

If we want to use the program to add two strings, the strings must be
enclosed in quotes for `eval`

to recognize the texts as string
objects (without the quotes, `eval`

aborts with an error):

```
add_input.py
Give input: 'one string'
Give input: " and another string"
<type 'str'> + <type 'str'> becomes <type 'str'>
with value one string and another string
```

Not all objects are meaningful to add:

```
add_input.py
Give input: 3.2
Give input: [-1,10]
Traceback (most recent call last):
File "add_input.py", line 3, in <module>
r = i1 + i2
TypeError: unsupported operand type(s) for +: 'float' and 'list'
```

A similar program adding two arbitrary command-line arguments
reads ((`add_input.py`):

```
import sys
i1 = eval(sys.argv[1])
i2 = eval(sys.argv[2])
r = i1 + i2
print '%s + %s becomes %s\nwith value %s' % \
(type(i1), type(i2), type(r), r)
```

Another important example on the usefulness of `eval`

is to turn
formulas, given as input, into mathematics in the program. Consider
the program

```
from math import * # make all math functions available
import sys
formula = sys.argv[1]
x = eval(sys.argv[2])
result = eval(formula)
print '%s for x=%g yields %g' % (formula, x, result)
```

Two command-line arguments are expected: a formula and a number. Say
the formula given is `2*sin(x)+1`

and the number is 3.14. This
information is read from the command line as strings. Doing ```
x =
eval(sys.argv[2])
```

means `x = eval('3.14')`

, which is equivalent to ```
x
= 3.14
```

, and `x`

refers to a `float`

object. The `eval(formula)`

expression means `eval('2*sin(x)+1')`

, and the corresponding statement
`result = eval(formula`

is therefore effectively ```
result =
2*sin(x)+1
```

, which requires `sin`

and `x`

to be defined objects. The
result is a `float`

(approximately 1.003). Providing `cos(x)`

as the
first command-line argument creates a need to have `cos`

defined, so
that is why we import all functions from the `math`

module.
Let us try to run the program:

```
eval_formula.py "2*sin(x)+1" 3.14
2*sin(x)+1 for x=3.14 yields 1.00319
```

The very nice thing with using `eval`

in `x = eval(sys.argv[2])`

is that
we can provide mathematical expressions like `pi/2`

or even
`tanh(2*pi)`

, as the latter just effectively results in the
statement `x = tanh(2*pi)`

, and this works fine as long has we have
imported `tanh`

and `pi`

.

Having presented `eval`

for turning strings into Python code, we take
the opportunity to also describe the related `exec`

function to
execute a string containing arbitrary Python code, not only an
expression.

Suppose the user can write a formula as input to the
program, available to us in the form of a string object.
We would then like to turn this formula into a callable Python
function. For example, writing `sin(x)*cos(3*x) + x**2`

as the formula,
we would make the function

```
def f(x):
return sin(x)*cos(3*x) + x**2
```

This is easy with `exec`

: just construct the right Python syntax
for defining `f(x)`

in a string and apply `exec`

to the string,

```
formula = sys.argv[1]
code = """
def f(x):
return %s
""" % formula
from math import * # make sure we have sin, cos, exp, etc.
exec(code)
```

As an example,
think of `"sin(x)*cos(3*x) + x**2"`

as the first command-line
argument. Then `formula`

will hold this text, which is inserted into
the `code`

string such that it becomes

```
"""
def f(x):
return sin(x)*cos(3*x) + x**2
"""
```

Thereafter, `exec(code)`

executes the code as if we had written
the contents of the `code`

string directly into the program by hand.
With this technique, we can turn any user-given formula into a
Python function!
Let us now use this technique in a useful application. Suppose we have made a function for computing the integral \( \int_a^b f(x)dx \) by the Midpoint rule with \( n \) intervals:

```
def midpoint_integration(f, a, b, n=100):
h = (b - a)/float(n)
I = 0
for i in range(n):
I += f(a + i*h + 0.5*h)
return h*I
```

We now want to read \( a \), \( b \), and \( n \) from the command line as well
as the formula that makes up the \( f(x) \) function:

```
from math import *
import sys
f_formula = sys.argv[1]
a = eval(sys.argv[2])
b = eval(sys.argv[3])
if len(sys.argv) >= 5:
n = int(sys.argv[4])
else:
n = 200
```

Note that we import everything from `math`

and use `eval`

when
reading the input for `a`

and `b`

as this will allow the user to
provide values like `2*cos(pi/3)`

.
The next step is to convert the `f_formula`

for \( f(x) \) into a
Python function `g(x)`

:

```
code = """
def g(x):
return %s
""" % f_formula
exec(code)
```

Now we have an ordinary Python function `g(x)`

that we can ask
the integration function to integrate:

```
I = midpoint_integration(g, a, b, n)
print 'Integral of %s on [%g, %g] with n=%d: %g' % \
(f_formula, a, b, n, I)
```

The complete code is found in

```
integrate.py "sin(x)" 0 pi/2
integral of sin(x) on [0, 1.5708] with n=200: 1
```

(The quotes in `"sin(x)"`

are needed because of the parenthesis will
otherwise be interpreted by the shell.)
The examples in the previous section indicate that it can be handy
to ask the user for a formula and turn that formula into a Python
function.
Since this operation is so useful, we have made a special tool that
hides the technicalities. The tool is named
`StringFunction`

and works as follows:

```
>>> from scitools.StringFunction import StringFunction
>>> formula = 'exp(x)*sin(x)'
>>> f = StringFunction(formula) # turn formula into f(x) func.
```

The `f`

object now behaves as an ordinary Python function of `x`

:

```
>>> f(0)
0.0
>>> f(pi)
2.8338239229952166e-15
>>> f(log(1))
0.0
```

Expressions involving other independent variables than `x`

are also
possible.
Here is an example with the function
\( g(t) = Ae^{-at}\sin (\omega x) \):

```
g = StringFunction('A*exp(-a*t)*sin(omega*x)',
independent_variable='t',
A=1, a=0.1, omega=pi, x=0.5)
```

The first argument is the function formula, as before, but now we need
to specify the name of the independent variable (`'x'`

is default).
The other parameters in the function (\( A \), \( a \), \( \omega \), and \( x \)) must be
specified with values, and we use keyword arguments, consistent with
the names in the function formula, for this purpose. Any of the parameters
`A`

, `a`

, `omega`

, and `x`

can be changed later by calls like

```
g.set_parameters(omega=0.1)
g.set_parameters(omega=0.1, A=5, x=0)
```

Calling `g(t)`

works as if `g`

were a plain Python
function of `t`

, which
also stores all the parameters `A`

, `a`

, `omega`

, and
`x`

, and their values. You can use `pydoc`

to bring
up more documentation on the possibilities with `StringFunction`

.
Just run

```
pydoc scitools.StringFunction.StringFunction
```

A final important point is that `StringFunction`

objects are as
computationally efficient as hand-written Python functions.
(This property is quite remarkable, as a string formula will in most
other programming languages be much slower to evaluate than if the
formula were hardcoded inside a plain function.)