Python: should I use eval, exec or ...?

I am trying to make the following statement more flexible:

for posting in page.findAll(attrs = {"id": re.compile(r'''post\d+''')}): 

The next part is extracted dynamically from the CSV file and stored in a line (for example, a line called test). CSV is stored in a safe place, accessible only to administrators.

 attrs = {"id": re.compile(r'''post\d+''')} 

Is it possible to integrate a variable as follows using the test eval (test) or exec (test) instead of a simple test?

 for posting in page.findAll(test)): 
+4
source share
4 answers

If you want to run the code from user input (the contents of the file is entered), you will need eval or exec , by these names or some others (in particular, you need exec for operators - assignment of expression).

But you do not want (and should not) do this because it is evil, unsafe, completely unnecessary, etc. Release the task (just save the dict) and call re.compile , then you can use ast.literal_eval and you are completely safe (you still have to catch syntax errors and everything else that may go wrong to display a reasonable error message, but the malicious code should be close to the impossible, and it’s not so dirty). You can apply re.compile after download if you need.

+5
source

If you have absolutely no control over the source of the CSV, avoid, by all means, these types of downloads.

  • save regex as seriliazed data with pickle module (or better, just save the string)
  • Save data as JSON using json module
  • write it to a file using the csv module

Then do the opposite to get the data from the file.

If you cannot control CSV generation, try manually extracting data using the split or re module.

eval and exec are the β€œlast resort”. Do not use them unless you have other methods.

+1
source

The most secure is ast.literal_eval () :

 >>> args = ast.literal_eval('{"a":1}') >>> args {'a': 1} 

You can use it like:

 some_function_or_method(**args) 
+1
source

None of them are Python - you can write eries with named parameters and the necessary values ​​to call the function as a dictionary. In this case, the dictionary whose meaning is the key "attrs" is also a dictionary. Before calling the function, just add "**" to the dictionary name:

 test= {"attrs": {\"id\": re.compile(r'''post\d+''')} } for posting in page.findAll(**test}): (...) 
0
source

Source: https://habr.com/ru/post/1340033/


All Articles