Python Forum
eval lambda function with restricted context - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/forum-7.html)
+--- Forum: General Coding Help (https://python-forum.io/forum-8.html)
+--- Thread: eval lambda function with restricted context (/thread-16544.html)



eval lambda function with restricted context - Olivier - Mar-04-2019

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


RE: eval lambda function with restricted context - ichabod801 - Mar-04-2019

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?


RE: eval lambda function with restricted context - Olivier - Mar-04-2019

My code is of course a minimal working example. Instead of "exp(1)" there will be an abritray expression supplied by the user.


RE: eval lambda function with restricted context - ichabod801 - Mar-04-2019

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.


RE: eval lambda function with restricted context - Olivier - Mar-04-2019

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?"


RE: eval lambda function with restricted context - ichabod801 - Mar-04-2019

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.


RE: eval lambda function with restricted context - stranac - Mar-04-2019

(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.


RE: eval lambda function with restricted context - Olivier - Mar-04-2019

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