How is correct use of eval()

Hrvoje Niksic hniksic at xemacs.org
Tue Oct 12 12:28:09 EDT 2010


Nobody <nobody at nowhere.com> writes:

> Oh, look what's "new in version 2.6":
>
> 	> ast.literal_eval("7")
> 	7
> 	> ast.literal_eval("7") == 7
> 	True

Note that it doesn't work for some reasonable inputs involving unary and
binary plus, such as "[-2, +1]" or "2+3j".  This has been fixed in the
development (3.2) sources.

An interesting aspect of ast.literal_eval is that it merely uses the
public API to access the AST provided by the compiler.  One is therefore
free to "fix" literal_eval in 2.6 or 2.7 by defining their own similar
function with the desired flavor.  For example:

import ast
from itertools import imap, izip

def my_literal_eval(s):
    node = ast.parse(s, mode='eval').body
    return _convert(node)

_safe_names = {'None': None, 'True': True, 'False': False}
_safe_operands = (ast.Num, ast.UnaryOp, ast.BinOp)
_safe_unops = (ast.UAdd, ast.USub)
_safe_binops = (ast.Add, ast.Sub)

def _convert(node):
    if isinstance(node, ast.Str):
        return node.s
    elif isinstance(node, ast.Num):
        return node.n
    elif isinstance(node, ast.Tuple):
        return tuple(imap(_convert, node.elts))
    elif isinstance(node, ast.List):
        return list(imap(_convert, node.elts))
    elif isinstance(node, ast.Dict):
        return dict((_convert(k), _convert(v)) for k, v
                    in izip(node.keys, node.values))
    elif isinstance(node, ast.Name) and node.id in _safe_names:
            return _safe_names[node.id]
    elif isinstance(node, ast.UnaryOp) and \
         isinstance(node.op, _safe_unops) and \
         isinstance(node.operand, _safe_operands):
        operand = _convert(node.operand)
        if isinstance(node.op, ast.UAdd):
            return + operand
        else:
            return - operand
    elif isinstance(node, ast.BinOp) and isinstance(node.op, _safe_binops) \
         and isinstance(node.right, _safe_operands) \
         and isinstance(node.left, _safe_operands):
        left = _convert(node.left)
        right = _convert(node.right)
        if isinstance(node.op, ast.Add):
            return left + right
        else:
            return left - right
    raise ValueError('malformed expression: ' + repr(node))



More information about the Python-list mailing list