如何将变量的值放入字符串中(插入到字符串中)?

415
我想把一个 int 放进一个 string 中。这是我目前正在做的:
num = 40
plot.savefig('hanning40.pdf') #problem line

我需要对几个不同的数字运行程序,所以我想使用循环。但是像这样插入变量是不起作用的:

plot.savefig('hanning', num, '.pdf')

如何将变量插入Python字符串中?


参见

如果您正在尝试创建文件路径,请参阅如何从部分(例如到文件夹的路径、名称和扩展名)创建完整路径?以获取其他技术。通常最好使用专门用于创建路径的代码。

如果您正在尝试组装带有可变数据的URL,请不要使用普通字符串格式化,因为它容易出错且比必要的困难。有专门的工具可用。请参阅在Python中向给定的URL添加参数

如果您正在尝试组装SQL查询,请不要使用普通字符串格式化,因为这是一个重大的安全风险。这是“SQL注入”的原因,每年会使真正的公司损失巨额资金。例如,请参阅如何在Python中在SQL语句中使用变量以获取正确的技术。

如果你只想要输出字符串,你可以先这样准备它,或者如果你不需要这个字符串做其他事情,可以使用单个调用print来逐个打印输出的每个部分。有关这两种方法的详细信息,请参见如何在同一行上一次性打印多个内容(固定文本和/或变量值)?

9个回答

807

使用f-strings

plot.savefig(f'hanning{num}.pdf')

这是在3.6版本中新增的并且是新的首选方式。


使用str.format()

plot.savefig('hanning{0}.pdf'.format(num))

字符串拼接:

plot.savefig('hanning' + str(num) + '.pdf')

转换说明符

plot.savefig('hanning%s.pdf' % num)

使用本地变量名称(巧妙技巧):

plot.savefig('hanning%(num)s.pdf' % locals())

使用 string.Template

plot.savefig(string.Template('hanning${num}.pdf').substitute(locals()))

另请参阅:


22
为了使用多个参数的格式化字符串操作符,可以使用元组作为操作数:'foo %d, bar %d' % (foo, bar) - fiedl
15
你的巧妙技巧也适用于新的格式语法:plot.savefig('hanning{num}s.pdf'.format(**locals())) - pix
在调用全局变量的函数中使用locals()出现了问题,改为使用%globals()便解决了问题。 - lobi
应该有一种 -- 最好只有一种 -- 显而易见的方法来完成它。 - MAChitgarha
3
@MAChitgarha:这只是一种美好的愿望,但对于随着时间演变的语言来说并不可能实现。 - martineau
2
f-strings是首选的方式在可能的情况下:即当格式化可以立即完成为文字模板时。当需要保存模板并重复使用它或推迟使用它时,f-strings无法工作。在这些情况下,请使用.format方法。 - Karl Knechtel

211
在Python 3.6中引入了格式化字符串字面量(简称"f-strings"),现在可以使用更简洁的语法来编写此代码:

With the introduction of formatted string literals ("f-strings" for short) in Python 3.6, it is now possible to write this with a briefer syntax:

>>> name = "Fred"
>>> f"He said his name is {name}."
'He said his name is Fred.'

以问题中给出的示例为例,它会看起来像这样

plot.savefig(f'hanning{num}.pdf')

4
看起来f-strings与多行字符串兼容 - Stevoisiak

190
plot.savefig('hanning(%d).pdf' % num)
< p > % 运算符,在字符串后面使用时,允许您通过格式代码(在本例中为 %d)将值插入到该字符串中。有关更多详细信息,请参阅 Python 文档:

printf 样式的字符串格式化


52
注意,自Python 3.1起,%操作符已被弃用。新的首选方法是使用.format()方法,如PEP 3101中所讨论的并在Dan McDougall的回答中提到的。 - Chris Mueller
2
% 运算符并未被弃用 - 现在只是不再是首选方法。 - kaya3

20
你可以使用+作为普通的字符串连接函数,也可以使用str()
"hello " + str(10) + " world" == "hello 10 world"

8
虽然这个答案是正确的,但应该避免使用 + 来构建字符串,因为它非常昂贵。 - slayton
@slayton 而且这样更难阅读和编写。 - wjandrea

7

通常,您可以使用以下方式创建字符串:

stringExample = "someString " + str(someNumber)
print(stringExample)
plot.savefig(stringExample)

6

如果您想将多个值放入字符串中,可以使用 format 方法。

nums = [1,2,3]
plot.savefig('hanning{0}{1}{2}.pdf'.format(*nums))

会生成字符串 hanning123.pdf。这可以使用任何数组完成。

4

特殊情况

根据使用变量数据与字符串的原因,通用方法可能不适用。

如果您需要准备SQL查询

不要使用任何常规技术来组装字符串。相反,使用您的SQL库的参数化查询功能。

查询是代码,因此不应像普通文本那样考虑。使用库将确保任何插入的文本都被正确转义。如果查询的任何部分可能来自程序外部的任何方式,这就是恶意用户执行 SQL注入的机会。这被广泛认为是重要的计算机安全问题,每年给真正的公司造成巨大的损失,并给无数客户带来问题。即使您认为数据是“安全的”,使用其他方法也没有实际好处。

语法将取决于您使用的库,并且超出了本答案的范围。

如果您需要准备URL查询字符串

查看在Python中向给定的URL添加参数。不要自己做;没有实际理由使你的生活更加困难。

写入文件

虽然可以提前准备好字符串,但只需使用单独的.write调用写入每个数据可能更简单、更节省内存。当然,非字符串仍需要在写入之前转换为字符串,这可能会使代码变得复杂。这里没有一种适合所有情况的答案,但选择不当通常不会有太大关系。

如果你只是调用print

内置的print函数接受可变数量的参数,并且可以使用str将任何对象转换为字符串。在尝试字符串格式化之前,请考虑是否只需传递多个参数即可完成所需操作。(您还可以使用sep关键字参数控制参数之间的间距。)

# display a filename, as an example
print('hanning', num, '.pdf', sep='')

当然,程序拼接字符串可能有其他原因使其变得有用;在适当的情况下,请务必这样做。

重要的是要注意,print 是一个特例。只有那些明确写成这种方式的函数才能像这样工作。对于普通函数和方法,例如input或Matplotlib图的savefig方法,我们需要自己准备一个字符串。

字符串连接

Python支持使用+将两个字符串连接在一起,但不能用于字符串和其他类型之间。为了解决这个问题,我们需要显式地将其他值转换为字符串:'hanning' + str(num) + '.pdf'

基于模板的方法

解决该问题的大多数方法都涉及到拥有某种包含“占位符”的“模板”字符串,这些“占位符”显示应添加信息的位置,然后使用某些函数或方法添加缺失的信息。

f-strings

这是可能时推荐的方法。它看起来像f'hanning{num}.pdf'。要插入的变量名称直接出现在字符串中。需要注意的是,实际上并不存在“f-string”这样的东西;它不是单独的类型。相反,Python会提前转换代码:
>>> def example(num):
...     return f'hanning{num}.pdf'
... 
>>> import dis
>>> dis.dis(example)
  2           0 LOAD_CONST               1 ('hanning')
              2 LOAD_FAST                0 (num)
              4 FORMAT_VALUE             0
              6 LOAD_CONST               2 ('.pdf')
              8 BUILD_STRING             3
             10 RETURN_VALUE

因为它是一种特殊的语法,可以访问其他方法中未使用的操作码。

str.format

这是在f-strings不可用时推荐的方法,主要是因为模板字符串需要事先准备好并稍后填充。它看起来像'hanning{}.pdf'.format(num)或者'hanning{num}.pdf'.format(num=num)'。在这里,format是字符串内置的方法,可以通过位置或关键字接受参数。
特别是对于str.format,有用的是要知道内置的localsglobalsvars函数返回将变量名映射到这些变量内容的字典。因此,我们可以使用类似'{a}{b}{c}'.format(**locals())的东西,unpacking locals() 字典。

str.format_map

这是对.format的一种罕见变化。它看起来像'hanning{num}.pdf'.format_map({'num': num})。与其接受关键字参数,它接受一个映射作为单个参数。
这可能听起来并不是很有用 - 毕竟,与其使用'hanning{num}.pdf'.format_map(my_dict),我们可以很容易地写成'hanning{num}.pdf'.format(**my_dict)。但是,对于决定值的映射而言,这是非常有用的,而不是普通的dict。在这些情况下,使用**解包可能行不通,因为键集可能不能提前确定;而基于模板进行键解包是笨拙的(想象一下:对于每个占位符都有一个单独的参数'hanning{num}.pdf'.format(num=my_mapping[num]))。

string.Formatter

“string”标准库模块包含一个很少使用的“Formatter”类。使用它看起来像这样:“string.Formatter().format('hanning{num}.pdf', num=num)”。模板字符串再次使用相同的语法。这显然比仅在字符串上调用“.format”更加笨重;动机是允许用户子类化“Formatter”以定义模板字符串的不同语法。
以上所有方法都使用通用的“格式化语言”(尽管“string.Formatter”允许更改它);还有许多其他可以放在“{}”中的内容。解释它如何工作超出了本答案的范围;请参考文档。请记住,文字“{”和“}”需要通过加倍来转义。语法可能受C#的启发。
“%”运算符
这是一种传统的解决问题的方式,受到C和C++的启发。长期以来,已经被不鼓励使用,但仍得到支持。对于简单情况,它看起来像'hanning%s.pdf' % num。顾名思义,在模板中字面上的百分号'%'需要加倍进行转义。
它存在一些问题:
似乎转换说明符(在%后面的字母)应该与被插值的内容类型相匹配,但实际上并非如此。相反,该值将转换为指定的类型,然后从那里转换为字符串。这通常是不必要的;直接转换为字符串大多数情况下都有效,而先转换为其他类型并不能帮助大部分情况下。因此,几乎总是使用's'(除非您想要值的repr,使用'r')。尽管如此,转换说明符是语法的强制部分。
元组有特殊处理:在右侧传递元组是提供多个参数的方式。这是一个丑陋的特例,必须使用它,因为我们没有使用函数调用语法。因此,如果您实际上想将元组格式化为单个占位符,则必须将其包装在1元组中。
其他序列类型被特殊处理,不同的行为可能会出现问题。

string.Template

“string”标准库模块包含一个很少使用的“Template”类。实例提供“substitute”和“safe_substitute”方法,与内置的“.format”类似(当参数不匹配时,“safe_substitute”将保留占位符而不是引发异常)。这也应该被视为解决问题的遗留方法。
它看起来像“string.Template('hanning$num.pdf').substitute(num=num)”,受传统Perl语法启发。显然,这种方法比“.format”方法更加笨重,因为必须在方法可用之前使用单独的类。大括号({})可以选择性地用于变量名称周围,以避免歧义。与其他方法类似,模板中的文字“$”需要加倍转义。

0
我需要一个扩展版本:不仅仅是将单个数字嵌入字符串中,还需要生成一系列文件名,例如'file1.pdf','file2.pdf'等。这是它的工作方式:
['file' + str(i) + '.pdf' for i in range(1,4)]

3
列表推导式与 OP 的问题无关,您正在使用的字符串格式化技术已经在 顶部答案goggin13 的答案 中涵盖。请不要发布回答其他问题或重复解决方案的答案。请参见[答案]。无论如何,手动使用 str() 没有理由;例如,使用 f-strings 更容易:f'file{i}.pdf' - wjandrea

-1
你可以创建字典并在字符串中替换变量。
var = {"name": "Abdul Jalil", "age": 22}
temp_string = "My name is %(name)s. I am %(age)s years old." % var

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接