[英]Malformed String ValueError ast.literal_eval() with String representation of Tuple
我正在尝试从文件中读取元组的字符串表示形式,并将元组添加到列表中。 这是相关的代码。
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.parse
模块来解析表达式,然后使用ast.NodeVisitor
或ast.NodeTransformer
来确保没有不需要的语法或不需要的变量访问。 然后用compile
和eval
compile
得到结果。
这段代码与literal_eval
有点不同,因为这段代码实际上使用了eval
,但在我看来更容易理解,不需要深入挖掘 AST 树。 它专门只允许某些语法,明确禁止例如 lambdas、属性访问( foo.__dict__
非常邪恶)或访问任何被认为不安全的名称。 它可以很好地解析您的表达式,作为额外的内容,我还添加了Num
(浮点数和整数)、列表和字典文字。
此外,在 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)
来自ast.literal_eval()
的文档:
安全地计算表达式节点或包含 Python 表达式的字符串。 提供的字符串或节点只能由以下 Python 文字结构组成:字符串、数字、元组、列表、字典、布尔值和无。
Decimal
不在ast.literal_eval()
允许的列表中。
我知道这是一个老问题,但我认为找到了一个非常简单的答案,以防万一有人需要它。
如果将字符串引号放在字符串中 ("'hello'"),ast_literaleval() 将完全理解它。
您可以使用一个简单的函数:
def doubleStringify(a):
b = "\'" + a + "\'"
return b
或者可能更适合这个例子:
def perfectEval(anonstring):
try:
ev = ast.literal_eval(anonstring)
return ev
except ValueError:
corrected = "\'" + anonstring + "\'"
ev = ast.literal_eval(corrected)
return ev
如果输入是可信的(就您而言),请使用eval()
而不是ast.literal_eval()
) 。
raw_data = userfile.read().split('\n')
for a in raw_data :
print a
btc_history.append(eval(a))
这在 Python 3.6.0 中对我有用
就我而言,我解决了:
my_string = my_string.replace(':false', ':False').replace(':true', ':True')
ast.literal_eval(my_string)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.