为了账号安全,请及时绑定邮箱和手机立即绑定

如何将变量评估为 Python f 字符串

如何将变量评估为 Python f 字符串

qq_笑_17 2021-11-09 16:22:43
我想要一种评估 f 字符串的机制,其中要评估的内容在变量中提供。例如,x=7s='{x+x}'fstr_eval(s)对于我想到的用例,字符串s可能来自用户输入(用户信任的地方eval)。虽然eval在生产中使用通常是非常糟糕的做法,但也有明显的例外。例如,用户可能是在本地机器上工作的 Python 开发人员,他希望使用完整的 Python 语法来开发 SQL 查询。关于重复的注意事项:这里和这里有类似的问题。第一个问题是在模板的有限上下文中提出的。第二个问题虽然与这个问题非常相似,但已被标记为重复。因为这个问题的上下文与第一个问题有很大不同,我决定根据第二个问题之后自动生成的建议提出第三个问题:这个问题以前有人问过,已经有了答案。如果这些答案不能完全解决您的问题,请提出一个新问题。
查看完整描述

2 回答

?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

即使有值得信赖的用户,使用也eval应该只是最后的手段。


如果您愿意牺牲语法的灵活性以获得更多的安全性和控制,那么您可以使用str.format并提供它的整个范围。


这将不允许对表达式求值,但单个变量将被格式化到输出中。


代码

x = 3

y = 'foo'


s = input('> ')

print(s.format(**vars()))

例子

> {x} and {y}

3 and foo


查看完整回答
反对 回复 2021-11-09
?
ibeautiful

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

可能还有其他我没有注意到的陷阱,但出于许多目的,我认为这已经足够了。


查看完整回答
反对 回复 2021-11-09
  • 2 回答
  • 0 关注
  • 136 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号