为什么我尝试格式化一个元组时会出现“TypeError:not all arguments converted during string formatting”错误?

147

我想使用%风格的字符串格式化来打印一个元组:

tup = (1,2,3)
print("this is a tuple: %s." % (tup))

我期望它打印出类似于This is a tuple: (1,2,3).的内容,但是实际上我得到了一个错误,提示TypeError: not all arguments converted during string formatting

这是什么问题,我该如何解决?


在编辑这个问题以使其更加清晰和现代化时,我保留了原始示例中一个有趣的方面:括号围绕着tup。这些括号对于%语法来说不是必需的,并且也不会创建一个元组。可能 OP 理解为需要包装元组(在这里的答案中描述),但只是使用方法错误。关于该问题的更多信息,请参见如何创建一个只包含一个元素的“单例”元组

16个回答

223
>>> thetuple = (1, 2, 3)
>>> print("this is a tuple: %s" % (thetuple,))
this is a tuple: (1, 2, 3)

创建一个只包含所需元组的单例元组,即 (thetuple,) 部分是关键。

1
在Python 3中,print是一个函数而非语句,因此你需要写成print(....)的形式。 - Jürgen Gmach

63

% 语法已过时,请使用更简单和易读的 str.format 语法:

t = 1,2,3
print('this is a tuple: {0}.'.format(t))

我为元组中只有一个项目的情况添加了一条评论到这个https://dev59.com/7nM_5IYBdhLWcg3wQQvw#26249755。 - Jacob CUI
我从来不知道为什么已经过时,但我现在总是盲目地使用str.format。不管那些,我对完整的限定符很感兴趣,因为简单的{0}并不是完整的限定符,而只是一个位置指示器。对于一个int,我所说的完整限定符将是{0:d}(或者如果要打印的int出现在str.format方法中的第四个位置,则为{3:d})。我尝试使用{0:s}限定符打印元组,但它不起作用。那么,像元组这样的东西的完整限定符是什么? - Ray
1
@Ray,那不太合理。你可以在文档中找到许多选项。如果您想使用 str 打印某些内容,则可以使用 {!s},但这是默认值,因此无需使用它。如果您想改用 repr,则可以使用{!r}。与 % 不同,对于整数,没有必要加上 d - Antimony
3
我喜欢使用“%”语法,因为它比新格式更简洁,而且非常类似于我喜欢的C字符串格式。 - Paulus
1
请注意,即使在Python 3上,仍不完全过时。实际上,如果您在logging模块中使用.format语法,pylint甚至会抱怨:https://dev59.com/PlsW5IYBdhLWcg3wwZcP#34634301 - Mike Williamson

53

正确的方法是:

>>> thetuple = (1, 2, 3)
>>> print("this is a tuple: %s" % (thetuple,))
this is a tuple: (1, 2, 3)

在 Python 3.x 中,% 字符串操作仍然被支持,并且使得将元组(或列表)格式化为单独的值更加容易。对于这种情况,使用 .format 将需要一些额外的工作 - 要么将值作为单独的参数传递,要么需要索引该序列:
>>> tup = (1,2,3)
>>> print("First: %d, Second: %d, Third: %d" % tup)
First: 1, Second: 2, Third: 3
>>> print('First: {}, Second: {}, Third: {}'.format(1,2,3))
First: 1, Second: 2, Third: 3
>>> print('First: {0[0]}, Second: {0[1]}, Third: {0[2]}'.format(tup))
First: 1, Second: 2, Third: 3

% 运算符还可以用于验证参数的类型,使用不同的格式化代码(%s%d%i),而 .format() 仅支持两个转换标志'!s''!r'


我已经开始使用format()方法了,但是%方法的这个优点(能够格式化元组中的每个元素并进行转换)很大,所以我想回到%方法。谢谢。 - Bill
2
你也可以为每个元素指定格式。'{:d}{:s}'.format(1, '2') - zk82
14
“星号解包”元组可以很好地与 .format 一起使用: tup = (1,2,3); print('First: {}, Second: {}, Third: {}'.format(*tup)) - m-dz
1
这是错误的。.format 语法确实允许类型检查。!s!r 是一个单独的特性。我们可以使用例如 '{:d}'.format(x) 指定所需的类型,这仅在 x 是整数时才有效。 - Karl Knechtel

27
>>> tup = (1, 2, 3)
>>> print "Here it is: %s" % (tup,)
Here it is: (1, 2, 3)
>>>

在这里,(tup,) - 有尾随逗号 - 是包含元组的元组。外部元组是%运算符的参数。内部元组是其内容,实际上会被打印出来。如果没有尾随逗号,(tup) 就和 tup 是一样的 - 括号只是普通的分组括号。

13
尽管这个问题很老并且有很多不同的答案,但我仍然想添加我的观点,认为最符合“Python风格”的也是最易读/简洁的答案。
由于通用元组打印方法已经被Antimony正确地展示了,因此这是每个元素分别打印的补充方法,正如Fong Kah Chun使用的%s语法所示。
有趣的是,它只在评论中提到过,但使用星号运算符来解包元组,在使用str.format方法打印元组元素时,可以获得完全的灵活性和易读性。
tup = (1, 2, 3)
print('Element(s) of the tuple: One {0}, two {1}, three {2}'.format(*tup))

这样做还可以避免在打印单元素元组时打印尾逗号,就像Jacob CUI通过replace所规避的那样。(尽管我个人认为,如果想要在打印时保留类型表示,则尾逗号表示是正确的):
tup = (1, )
print('Element(s) of the tuple: One {0}'.format(*tup))

9

除了其他答案中提出的方法,自从Python 3.6以来,我们还可以使用字面字符串插值(f-strings):

>>> tup = (1,2,3)
>>> print(f'this is a tuple: {tup}.')
this is a tuple: (1, 2, 3).

请参阅如何将变量的值放入字符串中(将其插入到字符串中)?以获取技术的完整概述。 - Karl Knechtel

8

这个例子没有用到字符串格式化,但是你应该能够这样做:

print('this is a tuple ', (1, 2, 3))

如果你真的想使用字符串格式化:
print('this is a tuple %s' % str((1, 2, 3)))
# or
print('this is a tuple %s' % ((1, 2, 3),))

8
t = (1, 2, 3)

# the comma (,) concatenates the strings and adds a space
print "this is a tuple", (t)

# format is the most flexible way to do string formatting
print "this is a tuple {0}".format(t)

# classic string formatting
# I use it only when working with older Python versions
print "this is a tuple %s" % repr(t)
print "this is a tuple %s" % str(t)

6

首先尝试将元组明确地转换为字符串:

t = (1,2,3)

print("This is a tuple: %s" % str(t))

Python支持在字符串上使用%运算符来对字符串进行printf-style formatting。 在这里,由于我们使用了%s占位符,因此传递一个字符串(使用str(t)创建)作为值是有意义的。

5
请注意,如果元组只有一个项,将会添加一个逗号。例如:
t = (1,)
print 'this is a tuple {}'.format(t)

你会得到:
'this is a tuple (1,)'

在某些情况下,例如您想要获取一个带引号的列表以在MySQL查询字符串中使用
SELECT name FROM students WHERE name IN ('Tom', 'Jerry');

你需要考虑在格式化后使用replace(',)', ')')来去除尾部逗号,因为可能元组只有一个项目,例如('Tom',),所以需要去除尾部逗号。
query_string = 'SELECT name FROM students WHERE name IN {}'.format(t).replace(',)', ')')

请在输出中提供一个可行的方法来删除这个逗号。

1
我通常更喜欢像这样的写法:'这是一个元组 ({})'.format(', '.join(map(str, t)))。这样你就不必担心在格式化字符串中弄乱现有的逗号或括号了。 - Antimony
1
在数据库查询中不应使用 format()。每个库都有适用的方法来处理这个问题。 - Konrad Talik
@ktalik,显然你没有理解这个。format()与数据库查询无关。format()是Python字符串操作的常用函数。请查看https://docs.python.org/2/library/string.html,你会从中学到东西的。记住,它与数据库查询无关。 - Jacob CUI
使用从用户收集的值与format()一起可能会导致SQL注入。在将其放入查询之前,验证输入值更加安全。请参阅以下指南以获取更多信息:https://dev.mysql.com/doc/connector-python/en/connector-python-coding.html 您还可以将参数值转换为数据库类型字符串表示,然后将其粘贴到查询字符串中。请查看http://initd.org/psycopg/docs/usage.html,在那里您可以看到一个使用`%`运算符的反例和一个使用`execute()`方法的解决方案,其中查询参数被传递给方法参数。 - Konrad Talik
1
@Paul Rooney 请注意,如果元组只有一个项目,则会添加尾随逗号。但是,如果使用不正确,它会造成麻烦。此外,格式化方法可以用于形成 SQL 查询。批评者们从哪里来的? - Jacob CUI

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