ValueError: malformed node or string with ast.literal_eval() when adding a Keras layer
ValueError: malformed node or string with ast.literal_eval() when adding a Keras layer
我想构建一个评估字符串的 Keras 模型。如果我执行以下操作:
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
model.add(Dense(units=10, input_shape=(10,), activation='softmax'))
它工作正常。我可以看到 model.summary()
.
但是,当我使用 ast.literal_eval()
添加图层时
from keras.models import Sequential
from keras.layers import Dense
import ast
model = Sequential()
code = "model.add( Dense( input_shape=(10,), units=10, activation='softmax' ) )"
ast.literal_eval(code)
下一个 ValueError
:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/ast.py", line 84, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.5/ast.py", line 83, in _convert
raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Call object at 0x7efc40c90e10>
如果我使用 eval
而不是 ast.literal_eval
,它也可以。
我正在使用 python3.5.
一个大错误:literal_eval
仅适用于 文字 。在这种情况下,我有一个 Call.
函数literal_eval
首先解析字符串。
来自 /usr/lib/python3.5/ast.py:第 38-46 行
def 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')
此时,node_or_string
是Expression
的一个实例。然后,literal_eval
获取正文。
来自 /usr/lib/python3.5/ast.py:第 47-48 行
if isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
最后,literal_eval
检查正文的类型 (node_or_string
)。
来自 /usr/lib/python3.5/ast.py:第 49-84 行
def _convert(node):
if 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)) and \
isinstance(node.operand, (Num, UnaryOp, BinOp)):
operand = _convert(node.operand)
if isinstance(node.op, UAdd):
return + operand
else:
return - operand
elif isinstance(node, BinOp) and \
isinstance(node.op, (Add, Sub)) and \
isinstance(node.right, (Num, UnaryOp, BinOp)) and \
isinstance(node.left, (Num, UnaryOp, BinOp)):
left = _convert(node.left)
right = _convert(node.right)
if isinstance(node.op, Add):
return left + right
else:
return left - right
raise ValueError('malformed node or string: ' + repr(node))
return _convert(node_or_string)
如果初始代码是 ast.literal_eval('1+1')
(例如),现在 node_or_string
将是 BinOp
的一个实例。但在以下情况下:
code = "model.add( Dense( input_shape=(10,), units=10, activation='softmax' ) )"
ast.literal_eval(code)
主体将是 Call
的实例,它不会出现在函数的有效类型中。
例如:
import ast
code_nocall = "1+1"
node = ast.parse(code_nocall, mode='eval')
body = node.body
print(type(body)) # Returns <class '_ast.BinOp'>
code_call = "print('hello')"
node = ast.parse(code_call, mode='eval')
body = node.body
print(type(body)) # Returns <class '_ast.Call'>
解决方案
到目前为止,我找到的最好的解决方案是手动执行该过程,而不是直接使用 eval
。有了这个功能:
import ast
def eval_code(code):
parsed = ast.parse(code, mode='eval')
fixed = ast.fix_missing_locations(parsed)
compiled = compile(fixed, '<string>', 'eval')
eval(compiled)
现在可以使用了:
eval_code("print('hello world')")
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
code = "model.add( Dense( input_shape=(10,), units=10, activation='softmax' ) )"
eval_code(code)
我想构建一个评估字符串的 Keras 模型。如果我执行以下操作:
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
model.add(Dense(units=10, input_shape=(10,), activation='softmax'))
它工作正常。我可以看到 model.summary()
.
但是,当我使用 ast.literal_eval()
from keras.models import Sequential
from keras.layers import Dense
import ast
model = Sequential()
code = "model.add( Dense( input_shape=(10,), units=10, activation='softmax' ) )"
ast.literal_eval(code)
下一个 ValueError
:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.5/ast.py", line 84, in literal_eval
return _convert(node_or_string)
File "/usr/lib/python3.5/ast.py", line 83, in _convert
raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Call object at 0x7efc40c90e10>
如果我使用 eval
而不是 ast.literal_eval
,它也可以。
我正在使用 python3.5.
一个大错误:literal_eval
仅适用于 文字 。在这种情况下,我有一个 Call.
函数literal_eval
首先解析字符串。
来自 /usr/lib/python3.5/ast.py:第 38-46 行
def 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')
此时,node_or_string
是Expression
的一个实例。然后,literal_eval
获取正文。
来自 /usr/lib/python3.5/ast.py:第 47-48 行
if isinstance(node_or_string, Expression):
node_or_string = node_or_string.body
最后,literal_eval
检查正文的类型 (node_or_string
)。
来自 /usr/lib/python3.5/ast.py:第 49-84 行
def _convert(node):
if 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)) and \
isinstance(node.operand, (Num, UnaryOp, BinOp)):
operand = _convert(node.operand)
if isinstance(node.op, UAdd):
return + operand
else:
return - operand
elif isinstance(node, BinOp) and \
isinstance(node.op, (Add, Sub)) and \
isinstance(node.right, (Num, UnaryOp, BinOp)) and \
isinstance(node.left, (Num, UnaryOp, BinOp)):
left = _convert(node.left)
right = _convert(node.right)
if isinstance(node.op, Add):
return left + right
else:
return left - right
raise ValueError('malformed node or string: ' + repr(node))
return _convert(node_or_string)
如果初始代码是 ast.literal_eval('1+1')
(例如),现在 node_or_string
将是 BinOp
的一个实例。但在以下情况下:
code = "model.add( Dense( input_shape=(10,), units=10, activation='softmax' ) )"
ast.literal_eval(code)
主体将是 Call
的实例,它不会出现在函数的有效类型中。
例如:
import ast
code_nocall = "1+1"
node = ast.parse(code_nocall, mode='eval')
body = node.body
print(type(body)) # Returns <class '_ast.BinOp'>
code_call = "print('hello')"
node = ast.parse(code_call, mode='eval')
body = node.body
print(type(body)) # Returns <class '_ast.Call'>
解决方案
到目前为止,我找到的最好的解决方案是手动执行该过程,而不是直接使用 eval
。有了这个功能:
import ast
def eval_code(code):
parsed = ast.parse(code, mode='eval')
fixed = ast.fix_missing_locations(parsed)
compiled = compile(fixed, '<string>', 'eval')
eval(compiled)
现在可以使用了:
eval_code("print('hello world')")
from keras.models import Sequential
from keras.layers import Dense
model = Sequential()
code = "model.add( Dense( input_shape=(10,), units=10, activation='softmax' ) )"
eval_code(code)