Python 格式错误的字符串 ValueError ast.literal_eval() 与元组的字符串表示
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14611352/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Malformed String ValueError ast.literal_eval() with String representation of Tuple
提问by Sinthet
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))
Here is the output:
这是输出:
(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
回答by NPE
From the documentationfor ast.literal_eval():
从文档中ast.literal_eval():
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, numbers, tuples, lists, dicts, booleans, and None.
安全地计算表达式节点或包含 Python 表达式的字符串。提供的字符串或节点只能由以下 Python 文字结构组成:字符串、数字、元组、列表、字典、布尔值和无。
Decimalisn't on the list of things allowed by ast.literal_eval().
Decimal不在 允许的列表中ast.literal_eval()。
回答by Antti Haapala
ast.literal_eval(located in ast.py) parses the tree with ast.parsefirst, 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 Decimalto the code you need to copy all the code and start over.
ast.literal_eval(位于ast.py)ast.parse首先用 解析树,然后用相当丑陋的递归函数评估代码,解释解析树元素并用它们的文字等价物替换它们。不幸的是,代码根本无法扩展,因此要添加Decimal到代码中,您需要复制所有代码并重新开始。
For a slightly easier approach, you can use ast.parsemodule to parse the expression, and then the ast.NodeVisitoror ast.NodeTransformerto ensure that there is no unwanted syntax or unwanted variable accesses. Then compile with compileand evalto get the result.
对于稍微简单的方法,您可以使用ast.parsemodule 来解析表达式,然后使用ast.NodeVisitororast.NodeTransformer来确保没有不需要的语法或不需要的变量访问。然后用compile和编译eval得到结果。
The code is a bit different from literal_evalin 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.
该代码与literal_eval实际使用的代码略有不同eval,但在我看来,它更易于理解,无需深入研究 AST 树。它专门只允许某些语法,明确禁止例如 lambdas、属性访问(foo.__dict__非常邪恶)或对任何被认为不安全的名称的访问。它可以很好地解析您的表达式,作为额外的内容,我还添加了Num(浮点数和整数)、列表和字典文字。
Also, works the same on 2.7 and 3.3
此外,在 2.7 和 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)
回答by nojco
I know this is an old question, but I think found a very simple answer, in case anybody needs it.
我知道这是一个老问题,但我认为找到了一个非常简单的答案,以防万一有人需要它。
If you put string quotes inside your string ("'hello'"), ast_literaleval() will understand it perfectly.
如果将字符串引号放在字符串中 ("'hello'"),ast_literaleval() 将完全理解它。
You can use a simple function:
您可以使用一个简单的函数:
def doubleStringify(a):
b = "\'" + a + "\'"
return b
Or probably more suitable for this example:
或者可能更适合这个例子:
def perfectEval(anonstring):
try:
ev = ast.literal_eval(anonstring)
return ev
except ValueError:
corrected = "\'" + anonstring + "\'"
ev = ast.literal_eval(corrected)
return ev
回答by HyperActive
Use eval()instead of ast.literal_eval()if the input is trusted (which it is in your case).
使用eval()而不是ast.literal_eval()输入是否受信任(在您的情况下)。
raw_data = userfile.read().split('\n')
for a in raw_data :
print a
btc_history.append(eval(a))
This works for me in Python 3.6.0
这在 Python 3.6.0 中对我有用

