2

I am pretty new to programming but I want to define a function like the following with user input:

function = raw_input('What function shall be used? ')     #user puts in "(1+1/x)^x"
def f(x):                                                 #using this to define
    y = (1+1/x)**x     
    return y

I hope it is clear what I try to do. Could you use input and define a priori that sin is used as math.sin? But how do I define the function afterwards?

Edited to add specification from the comments

Let's say the valid input is python code such as "(1+1/x)**x" like in the question. Could you now use eval to define a function f(x) which can be later used?

juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
Chiray
  • 133
  • 8
  • Give then way the question is worded, it sounds like you want to define your own mini-language, or computer algebra system. – juanpa.arrivillaga Jun 22 '17 at 17:43
  • You can use eval, but then you have to trust the user input will not blow up the server. – Paulo Scardine Jun 22 '17 at 17:43
  • 1
    http://www.sympy.org may help... – hiro protagonist Jun 22 '17 at 17:43
  • @PauloScardine no, you could not use `eval` because `eval` evaluates a *python expression*, but `(1+1/x)^x` does not mean `(1+1/x)**x` in python. – juanpa.arrivillaga Jun 22 '17 at 17:43
  • You can use `eval()` but don't... It's very unsafe and your users would need to know at least a bit of Python (e.g. something to the power of something else is defined as `**` not `^`) - and if they do, why not let them define their own modules that your app will load instead of requiring them to manually type math formulas? – zwer Jun 22 '17 at 17:44
  • @juanpa.arrivillaga - that's why I said that the users would need to know at least a bit of Python - good enough to write valid Python expressions. – zwer Jun 22 '17 at 17:45
  • @juanpa.arrivillaga Indeed one can use `eval`, just pass a context dictionary. – Paulo Scardine Jun 22 '17 at 17:46
  • @zwer yes, but at least given how the question is written, using `eval` wouldn't work. the point I'm trying to make is that this question is underspecified. – juanpa.arrivillaga Jun 22 '17 at 17:47
  • @juanpa.arrivillaga I am trying to implement interpolation with this. Therefore I need to work with the user's function. – Chiray Jun 22 '17 at 17:47
  • @PauloScardine that doesn't make `eval` any safer, if that is what you mean. If someone is going to the trouble of trying to exploit your `eval` vulnerability, that isn't going to stop them. I'm not sure how passing a context dictionary would help with translating `"(1+1/x)^x"` into the python expression `(1+1/x)**x` – juanpa.arrivillaga Jun 22 '17 at 17:48
  • @juanpa.arrivillaga you are repeating me, I said eval is unsafe in my first comment. – Paulo Scardine Jun 22 '17 at 17:49
  • @juanpa.arrivillaga what do you need to know? I want that an user can input a function like f(x) = x^2 and then the following code can work with this function – Chiray Jun 22 '17 at 17:49
  • @PauloScardine see my edit, because if that isn't what you meant then I don't know how passing a context dictionary is relevant. – juanpa.arrivillaga Jun 22 '17 at 17:49
  • @Chiray **so you want me to just imagine what is valid input?** Again, it *sounds* like you want to write a mini language, or a full-fledged CAS. I doubt that is what you *really* want, though. – juanpa.arrivillaga Jun 22 '17 at 17:50
  • If you are new to programming this is going to be an extreme challenge for you. You would have to create a full on CAS or at least some sort of equation parser, both of which are extremely difficult. Not to discourage you, but this is not a simple question that can be answered easily on SO. You will have to research this online, possibly with keywords such as 'how to code equation parser' or 'how to implement CAS' – victor Jun 22 '17 at 17:53
  • @juanpa.arrivillaga valid input is "sin", "cos", "^", and so on, as you would normally write a function in math calss. – Chiray Jun 22 '17 at 17:53
  • @PauloScardine _"[...]blow up the server"_ - Isn't that a tad extreme ;-) – Christian Dean Jun 22 '17 at 17:54
  • @Chiray in other words, when you are new to programming, it is [difficult to distinguish](https://xkcd.com/1425/) what is an easy problem and what is a hard problem. Additionally, beginners often don't appreciate how important it is to *properly specify requirements*. Your "valid inputs" are described as "stuff you would normally write a function in math class." But there are probably hundreds of different conventions, heck, it's probably different from math class to math class. Country to country. etc. – juanpa.arrivillaga Jun 22 '17 at 17:55
  • @Chiray So *now* your question boils down to "write an AI that can understand human natural language expressions that represent mathematical functions". That is not an easy problem. If you specify it properly, then *maybe it can become an easy problem*. Generally, using "etc" is not a good sign as far as precise specifications go. – juanpa.arrivillaga Jun 22 '17 at 17:56
  • @VictorC. Thank you for your answer! Do you know if there is any easy option in jupyter notebook using numpy similar? – Chiray Jun 22 '17 at 17:57
  • @Chiray what part of "extreme challenge" and "extremely difficult" makes you think there is an "easy option"? – juanpa.arrivillaga Jun 22 '17 at 18:00
  • @juanpa.arrivillaga I see what you mean. Let's say the valid input is python code such as "(1+1/x)**x" like in the question. Could you now use eval to define a function f(x) which can be later used? – Chiray Jun 22 '17 at 18:01
  • @Chiray https://stackoverflow.com/questions/594266/equation-parsing-in-python Try using this. It's not perfect but it may get you to where you need to go...just make sure not to release this or let other people use this without you knowing what they are doing. Again, this will be challenging--I recommend that if it is possible, you work on other "simpler" problems and become more accustomed with programming before you continue on implementing the CAS. Maybe avoid the user input for now and finish the interpolation system first? – victor Jun 22 '17 at 18:01
  • @juanpa.arrivillaga since numpy and matplotlib already has a whole varity of functions that in python don't exist – Chiray Jun 22 '17 at 18:04
  • @VictorC. Ok thank you! I finished the interpolation system, but it really looks like a rookie wrote it, so I when I am better at programming I will get back to this problem and solve it with all my might! Have you read "Learn python the hard way" and can you recommend it? – Chiray Jun 22 '17 at 18:12
  • @Chiray I have not, I learned Python by coding challenges (albeit simpler than what you're doing :) ), and it helps to work on these challenges and get input from other people so you can also get an idea of what would be difficult to implement and what is not. But I'm sure that the book is also a great resource! – victor Jun 22 '17 at 18:14
  • @ChristianDean yes, it is an exaggeration, but think how much damage you can do when you eval something like `import os; os.system("rm -rf ~")`. – Paulo Scardine Jun 22 '17 at 18:17

1 Answers1

3

As I commented, this can be done with something like eval, but is unsafe because you should never trust random user input.

>>> def expr_to_fn(expr):
...    expr = expr.replace('^', '**')
...    symbols = set(re.findall(r'([A-Z,a-z]+)', expr))
...    fn = eval("lambda {}: {}".format(",".join(symbols), expr))
...    return fn

>>> f = expr_to_fn("(1+1/x)^x")
>>> f(2)
2.25

The safe way is to implenet a DSL and a parser, or use a CAS (computer algebra system) like sympy, as suggested by Hiro.

Paulo Scardine
  • 73,447
  • 11
  • 124
  • 153
  • I think this is almost there, but it still doesn't deal with the issue of `sin`, `cos` and the like. However, this does make me understand what you meant by using a context dictionary, which could probably take this the rest of the way there. – juanpa.arrivillaga Jun 22 '17 at 18:13
  • Totally overlooked Hiro's comment but sympy might be what I was looking for. – Chiray Jun 22 '17 at 18:20
  • I will try what you did later tonight and see how far I can get with it, thank you! – Chiray Jun 22 '17 at 18:21
  • @juanpa.arrivillaga I accept your apology but I will have to left that as an exercise for the OP because I lack the time to post a complete work solution right now. – Paulo Scardine Jun 22 '17 at 18:26