I could do this with eval()
:
>>> s = 'hello=True,world="foobar"'
>>> eval('dict('+s+')')
{'hello': True, 'world': 'foobar'}
but with literal_eval()
:
>>> from ast import literal_eval
>>> literal_eval('dict('+s+')')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/ast.py", line 110, in literal_eval
return _convert(node_or_string)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/ast.py", line 109, in _convert
return _convert_signed_num(node)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/ast.py", line 83, in _convert_signed_num
return _convert_num(node)
^^^^^^^^^^^^^^^^^^
File "/usr/local/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/ast.py", line 74, in _convert_num
_raise_malformed_node(node)
File "/usr/local/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/ast.py", line 71, in _raise_malformed_node
raise ValueError(msg + f': {node!r}')
ValueError: malformed node or string on line 1: <ast.Call object at 0x1014cb940>
Q (part 1): Why would eval()
work but not literal_eval()
?
Q (part 2): Is there a name for the '+s+'
style/format?
Q (part 3): Is it possible to use something like the +s+
with literal_eval()
?
This isn't special syntax: +s+
doesn't have any atypical meaning. You're just concatenating strings together, the same way 'abc' + 'def'
evaluates to 'abcdef'
.
In this case, when you concatenate the string 'dict('
, the string 'hello=True,world="foobar"'
, and the string ')'
together, you get 'dict(hello=True,world="foobar")'
.
dict(hello=True,world="foobar")
is valid Python code (so eval
can run it), but it's not a valid literal definition (because dict
is a function call, not literal syntax), so ast.literal_eval()
correctly refuses it.