Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the use of eval() and exec() in Python

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article is about the usefulness of eval () and exec () in Python. The editor thinks it is very practical, so share it with you as a reference and follow the editor to have a look.

Python provides a number of built-in utility functions (Built-in Functions), 69 of which are listed in the latest Python 3 official documentation.

Most of the functions we use are frequently used, such as print (), open (), and dir (), while some functions, although not commonly used, can play an unusual role in some scenarios. Built-in functions can be "promoted", which means that they are unique and have the opportunity to show their talents.

Therefore, mastering the use of built-in functions has become a skill that we should light up.

1. The basic usage of eval

Syntax: eval (expression, globals=None, locals=None)

It has three parameters, where expression is an expression or code object of type string that is used for operations; globals and locals are optional parameters, and the default value is None.

Specifically, expression can only be a single expression and does not support complex code logic, such as assignment operations, loop statements, and so on. (PS: a single expression does not mean "simple and harmless", see section 4 below)

Globals is used to specify the global namespace of the runtime, the type is a dictionary, and the default is the built-in namespace of the current module. Locals specifies the local namespace of the runtime, the type is a dictionary, and the value of globals is used by default. When both are default, the scope of the eval function execution is followed. It is worth noting that these two do not represent real namespaces; they only work during the operation and are destroyed after the operation.

X = 10def func (): y = 20a = eval ('x + y') print ('a:', a) b = eval ('x + y: 1,'y: 2}) print ('x:'+ str (x) + y:'+ str (y)) print ('b:', b) c = eval ('x + y, {'x + y: 1,'y: 2}) Print ('x:'+ str (x) +'y:'+ str (y)) print ('c:', c) func ()

Output result:

A: 30x: 10 y: 20b: 3x: 10 y: 20c: 4

Thus, when a namespace is specified, the variable is looked up in the corresponding namespace. Also, their values do not overwrite the values in the actual namespace.

2. The basic usage of exec

Syntax: exec (object [, globals [, locals])

In Python2, exec is a statement, and Python3 transforms it into a function, just like print. Exec () is highly similar to eval (), and the meaning and function of the three parameters are similar.

The main difference is that the first argument to exec () is not an expression, but a code block, which means that it cannot evaluate an expression and return it, and that it can perform complex code logic, which is relatively more powerful, for example, when a new variable is assigned to a contemporary code block, the variable may survive in a namespace outside the function.

> x = 1 > y = exec ('x = 1 + 1') > print (x) > print (y) 2None

As you can see, the namespaces inside and outside exec () are connected, and variables are passed out, unlike the eval () function, which requires a variable to receive the result of the function's execution.

3. Discrimination of some details

Both functions are powerful and execute the contents of the string as valid code. This is a string-driven event that is of great significance. However, in the actual use process, there are a lot of small details, here are a few points that I know.

Common uses: convert strings to corresponding objects, such as string to list, string to dict,string to tuple, and so on.

> a = "[1 Python 2], [3 age': 4], [5 Python 6], [7 Python 8], [9 Python 0]] > print (eval (a)) {'name':' Python cat'{'name':' cat') 'age': 18} # is slightly different from eval > a = "my_dict = {' name': 'Python cat', 'age': 18}" > exec (a) > print (my_dict) {' name': 'Python cat', 'age': 18}

The return value of the eval () function is the result of its expression execution, and in some cases it will be None, for example, when the expression is a print () statement, or an append () operation of a list, the result of such an operation is None, so the return value of eval () will also be None.

> result = eval ('[] .append (2)') > print (result) None

The return value of the exec () function will only be None, regardless of the result of executing the statement, so there is no need to assign the exec () function. If return or yield are included in the executed statement, the values they produce do not work outside the exec function.

> result = exec ('1 + 1') > print (result) None

The globals and locals parameters in the two functions act as a whitelist to prevent data in scope from being abused by limiting the scope of the namespace.

The compiled code object of the conpile () function can be used as the first parameter of eval and exec. Compile () is also a magical function, and the last article I translated, "Python Operations: dynamically defining functions," demonstrated the operation of dynamically defining functions.

Paradoxical local namespaces: I mentioned earlier that variables in the exec () function can change the original namespace, but there are exceptions.

Def foo (): exec ('y = 1 + 1\ nprint (y)') print (locals ()) print (y) foo ()

According to the previous understanding, the expected result is that the variable y will be stored in the local variable, so the result of both prints will be 2, but the actual result is:

2 {'yearly: 2} Traceback (most recent call last):... (omit some error messages) print (y) NameError: name 'y'is not defined

Clearly saw that there is a variable y in the local namespace, why did you mistakenly say that it was undefined?

The reason is related to the compiler of Python, for the above code, the compiler will first parse the foo function into an ast (abstract syntax tree), and then store all variable nodes in the stack, when the parameter of exec () is just a string, the whole is a constant, and is not executed as code, so y does not exist yet. The variable y appears for the first time until the second print () is parsed, but because it is not fully defined, y will not be stored in the local namespace.

At run time, the exec () function dynamically creates the local variable y, but because the implementation mechanism of Python is that "the runtime local namespace is immutable", that is, y can never be a member of the local namespace, and an error is reported when print () is executed.

As for why the result taken out by locals () is y, why can't it represent the true local namespace? Why can't local namespaces be modified dynamically? You can check out the "pitfalls of Python dynamic assignment" I shared earlier. In addition, there is also a discussion on this issue on the official bug website. Check the address: https://bugs.python.org/issue4831.

If you want to take out the y after the execution of exec (), you can do this: Z = locals () ['y']. However, if you accidentally write the following code, an error will be reported:

Def foo (): exec ('y = 1 + 1') y = locals () ['y'] print (y) foo () # error report: KeyError:'y change the variable y to another variable will not make an error

KeyError means that there is no corresponding key in the dictionary. In this example, y makes a declaration, but cannot complete the assignment because of a circular reference, that is, the value corresponding to the key value is an invalid value, so an error is reported if it cannot be read.

There are four variants in this example, and I want to explain them with a set of self-consistent statements, but I have tried for a long time without success. Leave a message, and when I figure it out, I'll write a separate article.

4. Why should eval () be used cautiously?

Many dynamic programming languages have the eval () function, which works much the same, but, without exception, people will tell you to avoid using it.

Why should eval () be used cautiously? Mainly for security reasons, the eval function is likely to cause code injection problems for untrusted data sources.

> eval ("_ import__ ('os'). System (' whoami')") desktop-fa4b888\ pythoncat > eval ("_ import__ ('subprocess'). Getoutput (' ls ~')") # the result is slightly, and the content is the file information of the current path.

In the above example, my private data is exposed. To make matters worse, if you change the command to rm-rf ~, all files in the current directory will be deleted.

One limitation for the above example is to specify globals as {'_ builtins__': None} or {'_ builtins__': {}}.

> s = {'_ builtins__': None} > eval ("_ import__ ('os'). System (' whoami')", s) # error: TypeError: 'NoneType' object is not subscriptable

_ _ builtins__ contains names from the built-in namespace. Enter dir (_ _ builtins__) in the console and you will find the names of many built-in functions, exceptions, and other properties. By default, the globals parameter of the eval function implicitly carries _ _ builtins__, even if the globals parameter is {}, so if you want to disable it, you have to explicitly specify its value.

The above example maps it to None, which means that the built-in namespace available to eval is limited to None, thus limiting the ability of expressions to call built-in modules or attributes.

However, this approach is not foolproof, because there are still means to launch.

A loophole digger shared an idea in his blog, which was an eye-opener. The core code is the following sentence, which you can try to execute to see what is output.

> (). _ _ class__.__bases__ [0]. _ _ subclasses__ ()

For an explanation of this code, as well as further use, see the blog. (address: https://www.tuicool.com/articles/jeaqe2n)

There is also a blog post that not only mentions the means of the above example, but also provides a new way of thinking:

# warning: never execute the following code at your own risk. > > eval ('(lambda fc= (lambda n: [c 1 = "c" 2 = "in" 3 = "(). _ _ class__.__bases__ [0" language= "for"] [/ c]. _ _ subclasses__ () if c.roomnameplate _ = = n] [0]): fc ("function") (fc ("code") (0prime0mem0, "KABOOM", (), ", 0,"), {}) () ()') {"_ _ builtins__": None})

This line of code will cause Python to crash directly. Specific analysis is as follows: https://segmentfault.com/a/1190000011532358

In addition to the means of *, simple content can also initiate *. Writing like the following example will exhaust the server's computing resources in a short period of time.

> eval ("2 * * 888888888", {"_ _ builtins__": None}, {})

As mentioned above, we have visually demonstrated the harmfulness of the eval () function. However, even if Python experts use it carefully, there is no guarantee that there will be no mistakes.

In the official dumbdbm module, a security vulnerability was found (in 2014) that * * users can initiate * * when calling eval () by falsifying database files. (details: https://bugs.python.org/issue22885)

Similarly, last month (2019.02), a core developer raised a security issue for Python 3.8, proposing not to use the eval () function in logging.config, which is still in open state. (details: https://bugs.python.org/issue36022)

All this is enough to explain why eval () should be used with caution. By the same token, the exec () function should also be used with caution.

5. Safe alternative usage

Since there are all kinds of security risks, why create these two built-in methods? Why use them?

The reason is simple, because Python is a flexible and dynamic language. Unlike static languages, dynamic languages support code generation dynamically, and bug fixes can be implemented with only minor local modifications for projects that have been deployed.

Is there any way to use them relatively safely?

The literal () of the ast module is a safe alternative to eval (), and unlike the way eval () executes without checking, ast.literal () first checks whether the content of the expression is valid and legal. The literals it allows are as follows:

Strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None

If the content is illegal, an error will be reported:

Import astast.literal_eval ("_ _ import__ ('os'). System (' whoami')") reported an error: ValueError: malformed node or string

However, it also has disadvantages: the stack depth of the AST compiler is limited, and it may cause the program to crash if the parsed string content is too much or too complex.

As for exec (), there doesn't seem to be a similar alternative; after all, the content it can support is more complex and diverse.

Finally, there is a suggestion: figure out the differences and operational details (such as the previous local namespace contents), use them carefully, limit the available namespaces, and fully validate the data source.

Thank you for reading! This is the end of the article on "what is the use of eval () and exec () in Python?". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, you can share it for more people to see!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report