格式错误的String ValueError ast.literal_eval(),具有元组的字符串表示形式 [英] Malformed String ValueError ast.literal_eval() with String representation of Tuple

查看:112
本文介绍了格式错误的String ValueError ast.literal_eval(),具有元组的字符串表示形式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从文件中读取元组的字符串表示形式,并将元组添加到列表中.这是相关的代码.

I'm trying to read in a string representation of a Tuple from a file, and add the tuple to a list. Here's the relevant code.

raw_data = userfile.read().split('\n')
for a in raw_data : 
    print a
    btc_history.append(ast.literal_eval(a))

以下是输出:

(Decimal('11.66985'), Decimal('0E-8'))
Traceback (most recent call last):


File "./goxnotify.py", line 74, in <module>
    main()
  File "./goxnotify.py", line 68, in main
    local.load_user_file(username,btc_history)
  File "/home/unix-dude/Code/GoxNotify/local_functions.py", line 53, in load_user_file
    btc_history.append(ast.literal_eval(a))
  File "/usr/lib/python2.7/ast.py", line 80, in literal_eval
    return _convert(node_or_string)

  `File "/usr/lib/python2.7/ast.py", line 58, in _convert
   return tuple(map(_convert, node.elts))
  File "/usr/lib/python2.7/ast.py", line 79, in _convert
   raise ValueError('malformed string')
   ValueError: malformed string

推荐答案

ast.literal_eval(位于ast.py中)首先使用ast.parse解析树,然后使用相当难看的递归函数评估代码,从而解释解析树元素,并将其替换为它们的文字等效项.不幸的是,代码根本无法扩展,因此要将Decimal添加到代码中,您需要复制所有代码并重新开始.

ast.literal_eval (located in ast.py) parses the tree with ast.parse first, then it evaluates the code with quite an ugly recursive function, interpreting the parse tree elements and replacing them with their literal equivalents. Unfortunately the code is not at all expandable, so to add Decimal to the code you need to copy all the code and start over.

对于稍微简单一点的方法,可以使用ast.parse模块来解析表达式,然后使用ast.NodeVisitorast.NodeTransformer来解析,以确保没有不想要的语法或不想要的变量访问.然后用compileeval进行编译以得到结果.

For a slightly easier approach, you can use ast.parse module to parse the expression, and then the ast.NodeVisitor or ast.NodeTransformer to ensure that there is no unwanted syntax or unwanted variable accesses. Then compile with compile and eval to get the result.

该代码与literal_eval有点不同,因为该代码实际上使用了eval,但是我认为这更易于理解,并且不需要深入研究AST树.它专门只允许使用某些语法,例如lambdas,属性访问(foo.__dict__是非常邪恶的),或禁止访问任何不安全的名称.它可以很好地解析您的表达式,此外,我还添加了Num(浮点数和整数),列表和字典文字.

The code is a bit different from literal_eval in that this code actually uses eval, but in my opinion is simpler to understand and one does not need to dig too deep into AST trees. It specifically only allows some syntax, explicitly forbidding for example lambdas, attribute accesses (foo.__dict__ is very evil), or accesses to any names that are not deemed safe. It parses your expression fine, and as an extra I also added Num (float and integer), list and dictionary literals.

另外,在2.7和3.3上也可以使用

Also, works the same on 2.7 and 3.3

import ast
import decimal

source = "(Decimal('11.66985'), Decimal('1e-8'),"\
    "(1,), (1,2,3), 1.2, [1,2,3], {1:2})"

tree = ast.parse(source, mode='eval')

# using the NodeTransformer, you can also modify the nodes in the tree,
# however in this example NodeVisitor could do as we are raising exceptions
# only.
class Transformer(ast.NodeTransformer):
    ALLOWED_NAMES = set(['Decimal', 'None', 'False', 'True'])
    ALLOWED_NODE_TYPES = set([
        'Expression', # a top node for an expression
        'Tuple',      # makes a tuple
        'Call',       # a function call (hint, Decimal())
        'Name',       # an identifier...
        'Load',       # loads a value of a variable with given identifier
        'Str',        # a string literal

        'Num',        # allow numbers too
        'List',       # and list literals
        'Dict',       # and dicts...
    ])

    def visit_Name(self, node):
        if not node.id in self.ALLOWED_NAMES:
            raise RuntimeError("Name access to %s is not allowed" % node.id)

        # traverse to child nodes
        return self.generic_visit(node)

    def generic_visit(self, node):
        nodetype = type(node).__name__
        if nodetype not in self.ALLOWED_NODE_TYPES:
            raise RuntimeError("Invalid expression: %s not allowed" % nodetype)

        return ast.NodeTransformer.generic_visit(self, node)


transformer = Transformer()

# raises RuntimeError on invalid code
transformer.visit(tree)

# compile the ast into a code object
clause = compile(tree, '<AST>', 'eval')

# make the globals contain only the Decimal class,
# and eval the compiled object
result = eval(clause, dict(Decimal=decimal.Decimal))

print(result)

这篇关于格式错误的String ValueError ast.literal_eval(),具有元组的字符串表示形式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆