Using user defined variables/functions in eval [Python 3.4.2]?
Question: I have a calculator (python 3.4.2) that can do normal operations using eval.

    
    
    def calculator(user_input):
        if any(c not in config.valid_cal_chars for c in user_input):
            print("- Invalid Equation | Bad characters")
            return
        elif not any(c in user_input for c in "0123456789"):
            print("- Invalid Equation | No numbers found")
            return
        sys.stdout.write("calculating " + "-".join(gfx.load_sequence))
        time.sleep(0.1)
        print (" | 100%")
        try:
            current_ans = eval(user_input)
        except (SyntaxError, ZeroDivisionError, NameError, TypeError, ValueError):
            print ("- Invalid Equation | Error")
            return
        config.ans = current_ans
        print (current_ans)
    

Here is the config.py that config.ans, config.valid_cal_char is refering to:

    
    
    ans = ("0.0") 
    valid_cal_chars = ("0123456789-+/*ansqrt() \n")
    

And if you are wondering what the

    
    
    user_choice
    

variable is referring to, it is referring to a input function that I have
before this function. That part works, so no need to worry there.

However, I am wondering if it is possible to do something like this:

    
    
    input equation here: 4*4 #this would be saved as the user_input variable
    > 16 #the output of the equation
    input equation here: sqrt(ans) #this would use the previous answer saved in config.ans (ans) and the sqrt() to find the square root of the previous printed value, so:
    > 4
    

So typing ans would result in:

    
    
    input equation here: 1+1
    > 2
    input equation here: ans
    > 2
    

And using sqrt() would result in:

    
    
    input equation here: 2+2
    > 4
    input equation here: sqrt(4)
    > 2
    

So if you still don't get it, sqrt() find the square root of the value
inputted. ans uses the previous returned value. So combining the two
"sqrt(ans)" would give the square root of the previous returned value.

With the back ground info out of the way, what I want to do is to allow a user
to use these when calculating. While the "eval" may not work, I am happy to
use "exec" too (knowing the dangers). However, here is a multitool.py (the
main file) that imports the this file (functions.py) to use all the functions
that I have in there, including this one.

    
    
    import os, sys, glob, math, random, login, gfx, config, functions, time
    
    path = "******" #creates path to folder (can be changed by commenting this line out and creating new one)
    dirs = os.listdir( path ) #not used currently
    
    functions.load_sequence_complete()
    
    functions.username_login()
    time.sleep(0.05)
    functions.password_login()
    print ("\n[credentials have been verified! proceeding to main program " + "-".join(gfx.load_sequence) + "]\n")
    time.sleep(0.1)
    
    program = True
    while (program == True):
        user_choice = functions.choice_selecter()
        functions.validate_choice(user_choice)
    

If there are any other info that you need, please put that in the comments or
answers below so I can edit this to help you help me :)


Answer: You can do it in the first method , you can define `ans` as a global in the
start of the function, and then the result of `eval(user_input)` , and use
`ans` instead of `current_ans` everywhere.

How your function would look like , assuming everything works -

    
    
    def calculator(user_input):
        global ans
        if any(c not in config.valid_cal_chars for c in user_input):
            print("- Invalid Equation | Bad characters")
            return
        sys.stdout.write("calculating " + "-".join(gfx.load_sequence))
        time.sleep(0.1)
        print (" | 100%")
        try:
            ans = eval(user_input, {'ans':ans,'sqrt':sqrt},{})
        except (SyntaxError, ZeroDivisionError, NameError, TypeError, ValueError):
            print ("- Invalid Equation | Error")
            return
        config.ans = ans
        print (ans)
    

Please note I got rid of the `elif` part in the function, as otherwise, it
would not let an input like - `ans` \- go through - you may rethink how to
rewrite that.

Example/Demo -

    
    
    >>> def calculator(user_input):
    ...     global ans
    ...     if any(c not in "0123456789-+/*ansqrt() \n" for c in user_input):
    ...         print("- Invalid Equation | Bad characters")
    ...         return
    ...     time.sleep(0.1)
    ...     print (" | 100%")
    ...     try:
    ...         ans = eval(user_input, {'ans':ans,'sqrt':sqrt},{})
    ...     except (SyntaxError, ZeroDivisionError, NameError, TypeError, ValueError):
    ...         print ("- Invalid Equation | Error")
    ...         return
    ...     print (ans)
    ...
    >>>
    >>> calculator('1+2')
     | 100%
    3
    >>> calculator('ans')
     | 100%
    3
    >>> from math import sqrt
    >>> calculator('sqrt(ans)')
     | 100%
    1.7320508075688772
    

* * *

Though you can also use
[`eval`](https://docs.python.org/2/library/functions.html#eval) as -

    
    
    ans = eval(user_input, {'ans':ans,'sqrt':sqrt},{})
    

This would restrict eval to only take `ans` and `sqrt` as that names.

But still you should reconsider using `eval()` , as even after restricting the
globals and locals in it, users can still cause harm. Why? [Check
here.](http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html)

