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

How do I put a variable’s value inside a string (interpolate it into the string)?

提问人:Gish 提问时间:6/3/2010 最后编辑:Karl KnechtelGish 更新时间:5/24/2023 访问量:1183783

问:

我想把一个 .这是我目前正在做的事情:intstring

num = 40
plot.savefig('hanning40.pdf') #problem line

我必须为几个不同的数字运行程序,所以我想做一个循环。但是像这样插入变量是行不通的:

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

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


另请参阅

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

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

如果尝试组合 SQL 查询,请不要使用普通的字符串格式,因为这是一个重大的安全风险。这就是“SQL注入”的原因,每年都会花费大量资金。例如,请参阅如何在 Python 的 SQL 语句中使用变量?

如果只想打印(输出)字符串,可以先以这种方式准备它,或者如果不需要字符串进行任何其他操作,请使用单个调用来打印输出的每一部分。请参阅如何在同一行上同时打印多个内容(固定文本和/或变量值?),了解这两种方法的详细信息。

Python 字符串 变量

评论


答:

190赞 Amber 6/3/2010 #1
plot.savefig('hanning(%d).pdf' % num)

运算符在字符串后面时,允许您通过格式代码(在本例中为 )将值插入到该字符串中。有关详细信息,请参阅 Python 文档:%%d

printf 样式字符串格式

评论

52赞 Chris Mueller 7/16/2015
请注意,从 Python 3.1 开始,该运算符已弃用。新的首选方法是利用 PEP 3101 中讨论的方法,并在 Dan McDougall 的回答中提到。%.format()
2赞 kaya3 9/13/2021
运算符没有被弃用 - 它只是现在不是首选方式。%
20赞 goggin13 6/3/2010 #2

您可以用作普通的字符串连接函数,也可以用作 .+str()

"hello " + str(10) + " world" == "hello 10 world"

评论

8赞 slayton 12/27/2013
虽然这个答案是正确的,但应该避免使用构建字符串,因为它非常昂贵+
0赞 wjandrea 7/25/2022
@slayton 此外,阅读和写作也更难
7赞 Yehonatan 6/3/2010 #3

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

stringExample = "someString " + str(someNumber)
print(stringExample)
plot.savefig(stringExample)
810赞 Dan McDougall 6/3/2010 #4

使用 f 字符串

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())

使用字符串。模板

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

另请参阅:

评论

22赞 fiedl 8/8/2014
要将格式字符串运算符与多个参数一起使用,可以使用元组作为操作数:。'foo %d, bar %d' % (foo, bar)
15赞 pix 10/10/2014
你的巧妙技巧也适用于新的格式语法:plot.savefig('hanning{num}s.pdf'.format(**locals()))
0赞 lobi 2/14/2020
在调用全局变量的函数中使用局部变量 () 时出现问题;使用% globals()代替,这有效
3赞 martineau 2/8/2022
@MAChitgarha:一厢情愿的想法,但对于一种随着时间的推移而发展的语言来说,这是不可能的。
2赞 Karl Knechtel 9/4/2022
在可能的情况下,F 字符串是首选方式:即,当格式化可以立即完成到文本模板中时。当需要保存模板并重用它或推迟使用它时,f 字符串不起作用。在这些情况下,请使用该方法。.format
0赞 Raja 9/17/2016 #5

我需要一个扩展版本:我需要生成一系列形式的文件名,而不是在字符串中嵌入单个数字,而不是“file1.pdf”,“file2.pdf”等格式。这是它的工作原理:

['file' + str(i) + '.pdf' for i in range(1,4)]

评论

3赞 wjandrea 7/25/2022
列表推导与 OP 的问题无关,您使用的字符串格式化技术已经在顶部答案和 goggin13 的答案中介绍过。请不要发布回答不同问题的答案或重复的解决方案。请参阅如何回答。无论如何,没有理由手动使用;例如,使用 F 字符串要容易得多:str()f'file{i}.pdf'
211赞 joelostblom 5/26/2017 #6

随着 Python 3.6 中格式化字符串文字(简称“f-strings”)的引入,现在可以用更简短的语法来编写它:

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

使用问题中给出的示例,它看起来像这样

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

评论

4赞 Stevoisiak 10/31/2017
看来 f 字符串与多行字符串兼容
6赞 Jonathan R 1/9/2019 #7

如果你想在字符串中放入多个值,你可以利用format

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

将导致字符串 .这可以用任何数组来完成。hanning123.pdf

-1赞 abduljalil 2/28/2022 #8

您可以在字符串中创建 dict 和替换变量。

var = {"name": "Abdul Jalil", "age": 22}
temp_string = "My name is %(name)s. I am %(age)s years old." % var
4赞 Karl Knechtel 9/9/2022 #9

特殊情况

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

如果需要准备 SQL 查询

不要使用任何常用的技术来组装琴弦。相反,请使用 SQL 库的功能进行参数化查询。

查询是代码,因此不应将其视为普通文本。使用该库将确保正确转义任何插入的文本。如果查询的任何部分可能以任何方式来自程序外部,则这是恶意用户执行 SQL 注入的机会。这被广泛认为是重要的计算机安全问题之一,每年都会花费大量资金给实体公司带来麻烦,并给无数客户带来问题。即使您认为自己知道数据是“安全的”,使用任何其他方法也没有真正的好处。

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

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

请参阅在 Python 中向给定 URL 添加参数。不要自己动手;没有实际的理由让你的生活更艰难。

写入文件

虽然可以提前准备字符串,但使用单独的调用写入每条数据可能更简单、更节省内存。当然,在编写之前,非字符串仍然需要转换为字符串,这可能会使代码复杂化。这里没有一个放之四海而皆准的答案,但选择不当通常并不重要。.write

如果您只是打电话print

内置函数接受可变数量的参数,并且可以接受任何对象并使用 将其字符串化。在尝试字符串格式设置之前,请考虑是否只需传递多个参数即可实现所需的效果。(还可以使用关键字参数来控制参数之间的间距。printstrsep

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

当然,可能还有其他原因可以解释为什么程序组装字符串很有用;因此,请务必在适当的情况下这样做。

需要注意的是,这是一个特例。唯一以这种方式工作的函数是显式编写为以这种方式工作的函数。对于普通的函数和方法,比如 ,或者 Matplotlib 图的方法,我们需要自己准备一个字符串。printinputsavefig

串联

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

基于模板的方法

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

F 弦

如果可能,这是推荐的方法。它看起来像.要插入的变量的名称直接显示在字符串中。需要注意的是,实际上并不存在“f-string”这样的东西;它不是一个单独的类型。相反,Python 将提前翻译代码:f'hanning{num}.pdf'

>>> 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 字符串不可行时,建议使用这种方法 - 主要是因为模板字符串需要提前准备好并在以后填写。它看起来像 或 。这里,是内置于字符串中的方法,它可以按位置或关键字接受参数。'hanning{}.pdf'.format(num)'hanning{num}.pdf'.format(num=num)'format

特别是对于 ,了解内置的 和 函数返回将变量名称映射到这些变量内容的字典很有用。因此,我们可以使用类似 的东西,而不是像 ,解开字典。str.formatlocalsglobalsvars'{a}{b}{c}'.format(a=a, b=b, c=c)'{a}{b}{c}'.format(**locals())locals()

str.format_map

这是 的罕见变体。它看起来像.它不接受关键字参数,而是接受单个参数,即映射。.format'hanning{num}.pdf'.format_map({'num': num})

这听起来可能不是很有用 - 毕竟,我们可以很容易地写出 .但是,这对于动态确定值的映射很有用,而不是普通的 s。在这些情况下,解包可能不起作用,因为可能无法提前确定密钥集;并且尝试根据模板解压缩密钥是笨拙的(想象一下:,每个占位符都有一个单独的参数)。'hanning{num}.pdf'.format_map(my_dict)'hanning{num}.pdf'.format(**my_dict)dict**'hanning{num}.pdf'.format(num=my_mapping[num])

string.Formatter

标准库模块包含一个很少使用的类。使用它看起来像 .模板字符串再次使用相同的语法。这显然比仅仅调用字符串更笨拙;其动机是允许用户子类化,以便为模板字符串定义不同的语法。stringFormatterstring.Formatter().format('hanning{num}.pdf', num=num).formatFormatter

上述所有方法都使用一种通用的“格式化语言”(尽管允许更改它);还有很多其他的东西可以放在里面。解释它是如何工作的超出了这个答案的范围;请查阅文档。请记住,文字和字符需要通过加倍来转义。该语法可能受到 C# 的启发。string.Formatter{}{}

运营商%

这是解决问题的传统方法,受 C 和 C++ 的启发。长期以来,人们一直不鼓励这样做,但仍然受到支持。对于简单的情况,它看起来像。如您所料,模板中的文字符号需要加倍才能转义它们。'hanning%s.pdf' % num'%'

它有一些问题:

  • 似乎转换说明符()后面的字母应该与要插值的任何内容的类型匹配,但事实并非如此。相反,该值将转换为指定的类型,然后从那里转换为字符串。这通常不是必需的;大多数情况下,直接转换为字符串是有效的,而首先转换为其他类型在其余时间的大部分时间里都无济于事。所以几乎总是被使用(除非你想要值,使用 )。尽管如此,转换说明符是语法的强制性部分。%'s'repr'r'

  • 元组是专门处理的:在右侧传递元组是提供多个参数的方法。这是一个丑陋的特例,这是必要的,因为我们没有使用函数调用语法。因此,如果实际上要将元组格式化为单个占位符,则必须将其包装在 1 元组中。

  • 其他序列类型没有经过特殊处理,不同的行为可能是一个问题。

string.Template

标准库模块包含一个很少使用的类。实例提供的工作方式与内置方法类似(将保持占位符不变,而不是在参数不匹配时引发异常)。这也应被视为解决问题的遗留方法。stringTemplatesubstitutesafe_substitute.formatsafe_substitute

它看起来像 ,并且受到传统 Perl 语法的启发。它显然比方法更笨拙,因为在方法可用之前必须使用单独的类。可以选择在变量名称周围使用大括号 (),以避免歧义。与其他方法类似,模板中的文字需要加倍才能进行转义。string.Template('hanning$num.pdf').substitute(num=num).format{}'$'