45

我想将 f-string 与我的字符串变量一起使用,而不是使用字符串文字定义的字符串,"...".

这是我的代码:

name=["deep","mahesh","nirbhay"]
user_input = r"certi_{element}" # this string I ask from user  

for element in name:
    print(f"{user_input}")

此代码给出输出:

certi_{element}
certi_{element}
certi_{element}

但我想要:

certi_{deep}
certi_{mahesh}
certi_{nirbhay}

我怎样才能做到这一点?

4

4 回答 4

39

f"..."将表达式结果插入文字时,字符串很棒,但是您没有文字,您在单独的变量中有一个模板字符串。

您可以使用str.format()将值应用于该模板:

name=["deep","mahesh","nirbhay"]
user_input = "certi_{element}" # this string i ask from user  

for value in name:
    print(user_input.format(element=value))

使用名称(例如{element})的字符串格式占位符不是变量。您可以在调用的关键字参数中为每个名称分配一个值str.format()。在上面的例子中,element=value传入value变量的值来填充占位符element

f-strings 不同,{...}占位符不是表达式,您不能在模板中使用任意 Python 表达式。这是一件好事,您不希望最终用户能够在您的程序中执行任意 Python 代码。有关详细信息,请参阅格式字符串语法文档

您可以传入任意数量的名称;字符串模板不必使用其中任何一个。如果结合str.format()调用**mapping约定,可以使用任何字典作为值的来源:

template_values = {
    'name': 'Ford Prefect',
    'number': 42,
    'company': 'Sirius Cybernetics Corporation',
    'element': 'Improbability Drive',
}

print(user_input.format(**template_values)

以上将允许用户使用template_values他们模板中的任何名称,他们喜欢任意次数。

虽然您可以使用locals()andglobals()生成将变量名称映射到值的字典,但我不推荐这种方法。使用像上面这样的专用命名空间来限制可用的名称,并为您的最终用户记录这些名称。

于 2019-01-24T17:01:15.047 回答
32

如果你定义:

def fstr(template):
    return eval(f"f'{template}'")

然后你可以这样做:

name=["deep","mahesh","nirbhay"]
user_input = r"certi_{element}" # this string i ask from user  

for element in name:
    print(fstr(user_input))

作为输出给出:

certi_deep
certi_mahesh
certi_nirbhay

但请注意,用户可以在模板中使用表达式,例如:

import os  # assume you have used os somewhere
user_input = r"certi_{os.environ}"

for element in name:
    print(fstr(user_input))

你绝对不想要这个!

因此,一个更安全的选择是定义:

def fstr(template, **kwargs):
    return eval(f"f'{template}'", kwargs)

任意代码不再可能,但用户仍然可以使用字符串表达式,例如:

user_input = r"certi_{element.upper()*2}"

for element in name:
    print(fstr(user_input, element=element))

给出作为输出:

certi_DEEPDEEP
certi_MAHESHMAHESH
certi_NIRBHAYNIRBHAY

在某些情况下,这可能是需要的。

于 2019-08-21T18:47:17.980 回答
3

如果您希望用户有权访问您的命名空间,您可以这样做,但后果完全取决于您。您可以使用该format方法动态插值,而不是使用 f 字符串,语法非常相似。

如果您希望用户只能访问少数特定变量,您可以执行类似的操作

name=["deep", "mahesh", "nirbhay"]
user_input = "certi_{element}" # this string i ask from user  

for element in name:
    my_str = user_input.format(element=element)
    print(f"{my_str}")

您当然可以重命名用户输入的键与您使用的变量名称:

my_str = user_input.format(element=some_other_variable)

你可以让用户访问你的整个命名空间(或至少大部分)。请不要这样做,但请注意,您可以:

my_str = user_input.format(**locals(), **globals())

print(f'{my_str}')选择代替的原因print(my_str)是为了避免文字大括号被视为进一步的错误扩展的情况。例如,user_input = 'certi_{{{element}}}'

于 2019-01-24T17:00:07.163 回答
0

我正在寻找与您的问题类似的东西。我遇到了另一个问题的答案:https ://stackoverflow.com/a/54780825/7381826

使用这个想法,我调整了你的代码:

user_input = r"certi_"

for element in name:
    print(f"{user_input}{element}")

我得到了这个结果:

certi_deep
certi_mahesh
certi_nirbhay

如果您宁愿坚持问题中的布局,那么最后的编辑就可以了:

for element in name:
    print(f"{user_input}" "{" f"{element}" "}")

阅读所有其他问题的安全问题,我认为这种替代方案没有严重的安全风险,因为它没有使用 eval() 定义新函数。

我不是安全专家,所以如果我错了,请纠正我。

于 2021-11-16T06:29:47.840 回答