我想将 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}
我该怎么做?
另请参阅:如何推迟/延迟 f 字符串的评估?
literal
中时,
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
字符串不同,{...}
占位符是 not 表达式,您不能在模板中使用任意 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()
和
globals()
生成将变量名称映射到值的字典,但我不推荐这种方法。使用如上所述的专用命名空间来限制可用的名称,并为最终用户记录这些名称。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
这在某些情况下可能是需要的。
方法来动态插值,而不是使用 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}}}'
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() 定义新函数。
我不是安全专家,如果我错了,请纠正我。
name=["deep","mahesh","nirbhay"]
user_input = "certi_{element}" # this string I ask from user
for element in name:
print(eval("f'" + f"{user_input}" + "'"))