ValueError: ast.literal_eval()添加Keras层时出现格式错误的节点或字符串

2024-04-24 04:01:43 发布

您现在位置:Python中文网/ 问答频道 /正文

我想建立一个计算字符串的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。


Tags: orinfromimportnodemodelevalline
1条回答
网友
1楼 · 发布于 2024-04-24 04:01:43

一个大错误:literal_eval只对文本有效。在这种情况下,我有一个呼叫。

函数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_stringExpression的一个实例。然后,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)

相关问题 更多 >