New submission from Aaron Hall <aaronch...@yahoo.com>: Removing the closure seems to make the function about 10% faster.
Original source code at: https://github.com/python/cpython/blob/3.6/Lib/ast.py#L40 Empirical evidence: astle.py import timeit from ast import literal_eval as orig_literal_eval from ast import * def new_literal_eval(node_or_string): """ Safely evaluate an expression node or a string containing a Python expression. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None. """ if isinstance(node_or_string, str): node_or_string = parse(node_or_string, mode='eval') if isinstance(node_or_string, Expression): node_or_string = node_or_string.body node = node_or_string if isinstance(node, Constant): return node.value elif isinstance(node, (Str, Bytes)): return node.s elif isinstance(node, Num): return node.n elif isinstance(node, Tuple): return tuple(map(_convert, node.elts)) elif isinstance(node, List): return list(map(_convert, node.elts)) elif isinstance(node, Set): return set(map(_convert, node.elts)) elif isinstance(node, Dict): return dict((_convert(k), _convert(v)) for k, v in zip(node.keys, node.values)) elif isinstance(node, NameConstant): return node.value elif isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)): operand = _convert(node.operand) if isinstance(operand, _NUM_TYPES): if isinstance(node.op, UAdd): return + operand else: return - operand elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)): left = _convert(node.left) right = _convert(node.right) if isinstance(left, _NUM_TYPES) and isinstance(right, _NUM_TYPES): if isinstance(node.op, Add): return left + right else: return left - right raise ValueError('malformed node or string: ' + repr(node)) def main(): print('orig first, then new') print("'1.01'") print(min(timeit.repeat(lambda: orig_literal_eval('1.01')))) print(min(timeit.repeat(lambda: new_literal_eval('1.01')))) print("""'"1.01"'""") print(min(timeit.repeat(lambda: orig_literal_eval('"1.01"')))) print(min(timeit.repeat(lambda: new_literal_eval('"1.01"')))) print("'1'") print(min(timeit.repeat(lambda: orig_literal_eval('1')))) print(min(timeit.repeat(lambda: new_literal_eval('1')))) if __name__ == '__main__': main() Shell: $ python -m astle orig first, then new '1.01' 3.518230145502848 3.274753015923377 '"1.01"' 3.189016693752965 2.906869704238048 '1' 3.40557457956146 3.157061471625788 ---------- components: Library (Lib) messages: 304089 nosy: Aaron Hall priority: normal severity: normal status: open title: Unnecessary closure in ast.literal_eval type: performance _______________________________________ Python tracker <rep...@bugs.python.org> <https://bugs.python.org/issue31753> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com