简体   繁体   中英

How to use 'input' to input mathematical functions as variables in python 3.x

I want the user of my program to input a mathematical function of their choosing in numpy notation so that I can operate on it. For example:

import numpy as np
f=eval(input("Please input your function in numpy notation")

>>> "Please input your function in numpy notation"
>>> np.exp(x)
>>> NameError: name 'x' is not defined

with the code above, the user is inputting the exponential function, which is saved to a variable 'f' - more generally, I would like any mathematical function to be given as input and for it to be stored somehow as a python function. Pseudocode for this may be something like:

def F(x):
    f = eval(input("Please enter function in numpy notation:"))
    return f

which, if we use the exponential function again as an example, would be equivalent to hard coding:

def F(x):
    return np.exp(x)

One more example for clarity.

def F(x):
    f = eval(input("Please enter function in numpy notation:"))
    return f

>>> x*np.sin(x)

The user input x*np.sin(x) on the command line, which is equivalent to hard coding:

def F(x):
    return x*np.sin(x)

Is there anyway to do this?

Consider using numexpr module .

Example:

In [23]: import numexpr as ne

In [24]: a = np.arange(1e6)

In [25]: s = "sin(a)**2 + cos(a)**2"

In [27]: res = ne.evaluate(s)

In [28]: res
Out[28]: array([ 1.,  1.,  1., ...,  1.,  1.,  1.])

In [29]: res.shape
Out[29]: (1000000,)

it's also often faster than Numpy:

In [32]: %timeit ne.evaluate(s)
11.4 ms ± 256 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [33]: %timeit np.sin(a)**2 + np.cos(a)**2
41 ms ± 1.15 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

When you do f = eval(input("Please enter function in numpy notation:")) The input by the user gets interpreted as if you had written it in your file. So if your user inputs x+1 then your python script will try to do x+1 in that line.

If you want that line to create a function your user will have to enter something that evaluates to an actual function. That could be something like lambda x: x+1 which returns a function with one argument (x), calculating x+1 . Of course you could also add the lambda x: in your code. Small Example:

def F(x):
    return eval("lambda x:" + input("Please input a function in numpy notation!"))

x = 1
f = F(x)
print(f(x))

Of course this will require that the variable is always called x .

If you execute above code and enter eg x+1 the output is 2.

A simple solution would we to just wrap eval in a function and give it access to the names x and np :

import numpy

i = input("fn: ")  # enter function once

def f(x):
    return eval(i, {'x': x, 'np': numpy})

f(42)  # call it
f(0)  # call it again...

Note that eval is highly unsafe. Nothing prevents the user from entering evil code. If you care a tad bit about safety (or performance), @MaxU's answer is preferable.

If you plan to call the function often, it makes sense to pre-compile it:

i = input("fn: ")  # enter function once
i = compile(i, 'input', 'eval')

The resulting code object can be passed to eval just like a string.

Timing the input np.exp(x) :

%timeit f(0.5)  # Without pre-compilation
# 100000 loops, best of 3: 14.2 µs per loop

%timeit f(0.5)  # With pre-compilation
# 100000 loops, best of 3: 1.72 µs per loop  

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM