12
>>> 'string with no string formatting markers' % ['string']
'string with no string formatting markers'
>>> 'string with no string formatting markers' % ('string',)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting

我希望这两种情况都会引发 a TypeError,但事实并非如此。为什么不?

关于这个主题的Python 文档讨论了字符串、元组和字典,但没有提到列表。我对这种行为有点困惑。我已经能够在 Python 2.7 和 3.2 中复制它。

4

1 回答 1

6

仔细阅读,文档指出:

如果格式需要单个参数,则值可能是单个非tuple 对象。否则,值必须是tuple与格式字符串指定的项目数完全相同的 a,或者是单个映射对象(例如,字典)。

现在,在这种情况下,format不需要单个参数,因此文档告诉我们应该使用 atuple或映射作为参数;其他情况属于“未定义的行为”(正在发生的事情:行为在所有情况下都不一致)。

这可能应该被认为是这个问题的最终答案:如果字符串没有任何格式说明符,则使用 a list(或任何不同于tuple或映射的类型)应该简单地被认为是一个错误,它本身会导致未定义的行为。

因此,您应该始终使用tupleordict作为参数,否则您必须手动检查格式说明符或处理奇怪的行为。

在您的情况下,您可能可以使用(['string'], )代替来解决问题['string']


为什么结果行为似乎如此随机的可能“解释”:

似乎/的原始实现中有一个错误检查,而不是在这一行上使用:PyString_FormatPyUnicode_FormatPyMappingCheck

if (PyMapping_Check(args) && !PyTuple_Check(args) &&
     !PyObject_TypeCheck(args, &PyBaseString_Type))
    dict = args;

它使用了这个代码:

if (Py_TYPE(args)->tp_as_mapping && !PyTuple_Check(args) &&
    !PyObject_TypeCheck(args, &PyBaseString_Type))
    dict = args;

这是不等价的。例如set没有tp_as_mapping设置(至少在我几周前下载的 Python2.7.3 源代码中),而list确实设置了它。

这可能是为什么list(可能还有其他对象)不提高TypeErrorwhile set,int和许多其他对象的原因。

正如我之前在同一个答案中所说,我确实得到TypeErrorlists:

$ python2
Python 2.7.3 (default, Sep 26 2012, 21:53:58) 
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> 'some string' % []
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting

This probably shows that the above issue is not the only one here.

Looking at the source code I agree that, in theory, the number of arguments is not checked if the argument is not a tuple, but this would imply 'some string' % 5 -> 'some string' and not a TypeError, so there must be something fishy in that code.

于 2012-12-13T16:58:01.950 回答