Python Forum

Full Version: eval lambda function with restricted context
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hello,

I would like to create a lambda function accessing Numpy functions, and only them. I can do the following:

import numpy
eval('exp(1)', {'__builtins__': None}, numpy.__dict__)
Output:
2.7182818284590451
However, I get an error when I create a lambda function in that way:

f = eval('lambda x:exp(1)', {'__builtins__': None}, numpy.__dict__)
f(0)
Error:
TypeError: 'NoneType' object is not subscriptable
Could you explain why and provide a working example?

Olivier
Can you explain why you would want to do this? Why not just use lambda x: numpy.exp(1)? And why evaluate a lambda anyway?
My code is of course a minimal working example. Instead of "exp(1)" there will be an abritray expression supplied by the user.
Then I think it would be better to do this with a dictionary of the necessary functions. Parse out the function name and the parameters, find the actual function in the dictionary, and apply the parameters.
Sorry, my browser sent the message while I was writing it, against my will. I start again.

You want me to write a general parser for mathematical expressions? I won't do that! First, it is a huge work (I expect arbitrary mathematical expressions to be treated). Second, I already have the parser in the computer, and it is called Python! There should be a way to use it properly. The following way does what I want, but is not clean.
from numpy import *
f = eval('lambda x:exp(1)')
f(0)
Output:
2.718281828459045
It is not clean because, first, it clutters the namespace, second, it doesn't restrict the functions that can be accessed. My initial question can be rephrased into: "why does the example in this message work? and why does the code in the initial message doesn't work?"
You want to allow the user to enter arbitrarily complicated expressions and get the result? I would just have them use the Python interpreter. If you really want to do this, I think you need to make built-ins a dictionary. Making it an empty dictionary is probably going to cause problems evaluating things. You might want to copy the actual built-ins and delete what you don't want. I would only do this if the context is that the user is running the program on his own machine. Otherwise it is a huge security hole.
(Mar-04-2019, 08:02 PM)Olivier Wrote: [ -> ]why does the code in the initial message doesn't work?
The function you're creating doesn't have any locals, so python tries getting exp form globals.
Since you've defined globals as {'__builtins__': None}, you get an error.

One way to make this "work" would be:
f = eval('lambda x, exp=exp: exp(1)', {'__builtins__': None}, numpy.__dict__)
Note that, other than being awful code, this doesn't actually limit what functionality a user can access.
There are many ways to access functions and objects in python which don't require actually using their name.
Therefore, if you let a knowledgeable user eval arbitrary code, they can access pretty much any part of the language, no matter what args you use.
Regarding security, I know that it is not absolutely safe. But IMO it's better to do something partly than do nothing.

I think that Stranac gave a good hint! Use the globals! Accordingly, the following code is functional and seems to be satisfying for my need:

import numpy
symbol_table = numpy.__dict__.copy()
symbol_table['__builtins__'] = None         # remove built-in functions
f = eval('lambda x:exp(1)', symbol_table)
In my first post, I was not understanding the use of locals in the eval() function. I still do not understand exactly what it is meant to be used for, but I think that in the context of my question, the globals should be used.

Thank you for the help.

Olivier