我如何把一个变量的值在一个字符串(插值到字符串)?

我想把int放到string中。这就是我现在正在做的事情:

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

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

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

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


另见我如何连接str和int对象?如果你尝试使用+连接一个数字与一个字符串(或字符串之间,等),并得到一个错误消息。

如果您试图用可变数据组合URL, 不要使用普通字符串格式,因为这很容易出错,而且比必要的更难。有专门的工具可用。参见在Python中为给定URL添加参数

如果您试图组装一个SQL查询,不要使用普通字符串格式化,因为这是一个重大安全风险。这就是“SQL注入”的原因。其中每年花费真实公司大量的钱。参见示例Python:连接MySQL并执行查询的最佳实践和最安全的方式获得适当的技术。

1030981 次浏览
plot.savefig('hanning(%d).pdf' % num)

当跟在字符串后面时,%操作符允许你通过格式代码(在本例中是%d)将值插入到字符串中。要了解更多细节,请参阅Python文档:

printf-style String Formatting

你可以像使用str()一样使用+作为正常的字符串连接函数。

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

一般来说,你可以使用以下方法创建字符串:

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

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

参见:

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

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

在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')

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

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

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

你可以在你的字符串中使用字典和替换变量。

var = {"name": "Abdul Jalil", "age": 22}
temp_string = "My name is %(name)s. I am %(age)s years old." % var

特殊情况

根据为什么变量数据与字符串一起使用,通用方法可能不合适。

如果您需要准备一个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-string不可能时,这是推荐的方法——主要是因为模板字符串需要提前准备,然后再填充。它看起来像'hanning{}.pdf'.format(num)'hanning{num}.pdf'.format(num=num)'。这里,format是一个内置于字符串中的方法,它可以通过位置或关键字接受参数。

特别是对于str.format,知道内置的localsglobalsvars函数返回将变量名映射到这些变量内容的字典是很有用的。因此,我们可以使用'{a}{b}{c}'.format(**locals())拆包locals()字典,而不是像'{a}{b}{c}'.format(a=a, b=b, c=c)这样的字典。

str.format_map

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

这可能听起来不是很有用——毕竟,我们可以很容易地写'hanning{num}.pdf'.format(**my_dict)而不是'hanning{num}.pdf'.format_map(my_dict)。然而,这对于动态确定值的映射很有用,而不是普通的__abc2。在这些情况下,使用**解包可能无法工作,因为键集可能没有提前确定;并且尝试基于模板解包键是笨拙的(想象:'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类。实例提供了substitutesafe_substitute方法,其工作方式类似于内置的.format (safe_substitute将保持占位符完整,而不是在参数不匹配时引发异常)。这也应该被认为是解决问题的一种遗留方法。

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