2 回答

TA贡献1827条经验 获得超9个赞
即使有值得信赖的用户,使用也eval应该只是最后的手段。
如果您愿意牺牲语法的灵活性以获得更多的安全性和控制,那么您可以使用str.format并提供它的整个范围。
这将不允许对表达式求值,但单个变量将被格式化到输出中。
代码
x = 3
y = 'foo'
s = input('> ')
print(s.format(**vars()))
例子
> {x} and {y}
3 and foo

TA贡献1993条经验 获得超5个赞
这是我对 f-strings 进行更可靠评估的尝试,灵感来自kadee对类似问题的优雅回答。
但是,我想避免该eval方法的一些基本陷阱。例如,eval(f"f'{template}'")只要模板包含一个撇号就会失败,例如the string's evaluation成为f'the string's evaluation'它以语法错误评估。第一个改进是使用三撇号:
eval(f"f'''{template}'''")
现在在模板中使用撇号(大部分)是安全的,只要它们不是三重撇号。(三引号也可以。)一个值得注意的例外是字符串末尾的撇号:whatcha doin'变成f'''whatcha doin''''在第四个连续撇号处计算语法错误。以下代码通过去除字符串末尾的撇号并在计算后将它们放回去来避免此特定问题。
import builtins
def fstr_eval(_s: str, raw_string=False, eval=builtins.eval):
r"""str: Evaluate a string as an f-string literal.
Args:
_s (str): The string to evaluate.
raw_string (bool, optional): Evaluate as a raw literal
(don't escape \). Defaults to False.
eval (callable, optional): Evaluation function. Defaults
to Python's builtin eval.
Raises:
ValueError: Triple-apostrophes ''' are forbidden.
"""
# Prefix all local variables with _ to reduce collisions in case
# eval is called in the local namespace.
_TA = "'''" # triple-apostrophes constant, for readability
if _TA in _s:
raise ValueError("Triple-apostrophes ''' are forbidden. " + \
'Consider using """ instead.')
# Strip apostrophes from the end of _s and store them in _ra.
# There are at most two since triple-apostrophes are forbidden.
if _s.endswith("''"):
_ra = "''"
_s = _s[:-2]
elif _s.endswith("'"):
_ra = "'"
_s = _s[:-1]
else:
_ra = ""
# Now the last character of s (if it exists) is guaranteed
# not to be an apostrophe.
_prefix = 'rf' if raw_string else 'f'
return eval(_prefix + _TA + _s + _TA) + _ra
在不指定评估函数的情况下,该函数的局部变量是可访问的,因此
print(fstr_eval(r"raw_string: {raw_string}\neval: {eval}\n_s: {_s}"))
印刷
raw_string: False
eval: <built-in function eval>
_s: raw_string: {raw_string}\neval: {eval}\n_s: {_s}
虽然前缀_降低了意外碰撞的可能性,但可以通过传递适当的评估函数来避免该问题。例如,可以通过以下方式传递当前的全局命名空间lambda:
fstr_eval('{_s}', eval=lambda expr: eval(expr))#NameError: name '_s' is not defined
或更一般地,通过将合适的globals和locals参数传递给eval,例如
fstr_eval('{x+x}', eval=lambda expr: eval(expr, {}, {'x': 7})) # 14
我还包含了一种机制,\可以通过“原始字符串文字”机制选择是否应将其视为转义字符。例如,
print(fstr_eval(r'x\ny'))
产量
x
y
尽管
print(fstr_eval(r'x\ny', raw_string=True))
产量
x\ny
可能还有其他我没有注意到的陷阱,但出于许多目的,我认为这已经足够了。
添加回答
举报