python eval против ast.literal_eval против JSON-декодирования - PullRequest
16 голосов
/ 30 марта 2012

Я конвертирую 2 МБ данных в виде строки в dict. Входные данные сериализуются в формате JSON.

В любом случае, в настоящее время я использую ast.literal_eval, и я получаю нужный словарь, но затем, когда я попробовал просто запустить eval, кажется, он работает быстрее и также возвращает тот же результат.

Есть ли причина использовать модуль ast или модуль json, когда eval работает просто отлично?

Ответы [ 4 ]

27 голосов
/ 29 ноября 2013

Мне не очень нравится такое отношение к stackoverflow (и в других местах), когда люди говорят без контекста, что то, что они делают, небезопасно, и они не должны этого делать. Может быть, это просто отдельный скрипт для импорта некоторых данных, в таком случае, почему бы не выбрать самый быстрый или удобный способ?

В этом случае, однако, json.loads не только более безопасен, но и более чем в 4 раза быстрее (в зависимости от ваших данных).

In [1]: %timeit json.loads(data)
10000 loops, best of 3: 41.6 µs per loop

In [2]: %timeit eval(data)
10000 loops, best of 3: 194 µs per loop

In [3]: %timeit ast.literal_eval(data)
1000 loops, best of 3: 269 µs per loop

Если вы думаете об этом, имеет смысл, что json - такой более ограниченный язык / формат, чем python, поэтому он должен быть быстрее разбираться с оптимизированным парсером.

22 голосов
/ 30 марта 2012

Да, определенно есть причина: eval() это зло.Ваш код может считывать ненадежные данные однажды, и это позволит злоумышленнику запустить произвольный код на вашем компьютере.

Вам также не следует использовать ast.literal_eval() для декодирования JSON.Он не может декодировать каждую допустимую строку JSON и не предназначен для этой цели.Просто используйте json.loads(), это достаточно быстро.

16 голосов
/ 30 марта 2012

Нет.Если вы не выберете один из двух сценариев:

  1. Это не JSON!

    Кто-то вместо этого помещает __import__('os').system('rm -rf /') в файл.Вы костей.

  2. Это JSON, но не Python-подобная часть!

    Кто-то ставит true, false, null или Unicodeсбежать где-нибудь в этом.С Днем Рождения.

1 голос
/ 23 октября 2014

Точно не ответ, но следует отметить, что eval и literal_eval - это не одно и то же. ast.literal_eval не будет запускать произвольный код.

Тем не менее, я согласен с использованием JSON; Я просто хотел отметить, что eval != literal_eval

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...