为什么使用列表作为字符串格式化参数,即使没有 %s 标识符,也会返回原始字符串? [英] Why does using a list as a string formatting parameter, even with no %s identifier, return the original string?
问题描述
我希望这两种情况都会引发 TypeError
,但事实并非如此.为什么不呢?
关于这个主题的 Python 文档 讨论了字符串,元组和字典,但没有提到列表.我对这种行为有点困惑.我已经能够在 Python 2.7 和 3.2 中复制它.
仔细阅读,文档说明:
<块引用>如果格式需要单个参数,则值可能是单个非元组
目的.否则,值必须是一个 tuple
与数字由格式字符串或单个映射对象指定的项目(例如,字典).
现在,在这种情况下,format
不需要单个参数,因此文档告诉我们您应该使用 tuple
或映射作为参数;其他情况属于未定义行为"(这就是正在发生的事情:行为在所有情况下都不一致).
这可能应该被视为问题的最终答案:如果字符串没有任何格式说明符,则使用 list
(或任何不同于 tuple
或映射)本身应该简单地被视为导致未定义行为的错误.
由此可知,您应该始终使用 tuple
或 dict
作为参数,否则您必须手动检查格式说明符或处理奇怪的行为.
在您的情况下,您可以使用 (['string'], )
而不是 ['string']
来解决问题.
为什么结果行为似乎如此随机的可能解释":
在 PyString_Format<的原始实现中,检查似乎有问题/code>/
PyUnicode_Format
,而不是在 这一行:
if (PyMapping_Check(args) && !PyTuple_Check(args) &&!PyObject_TypeCheck(args, &PyBaseString_Type))字典 = args;
使用了这个代码:
if (Py_TYPE(args)->tp_as_mapping && !PyTuple_Check(args) &&!PyObject_TypeCheck(args, &PyBaseString_Type))字典 = args;
这是不等价的.例如 set
没有设置 tp_as_mapping
(至少在我几周前下载的 Python2.7.3 源代码中),而 list
确实设置了.
这可能是 list
(可能还有其他对象)不引发 TypeError
while, set
, int 的原因
和许多其他人这样做.
正如我之前在同一个答案中所说的,即使使用 list
s,我也会得到 TypeError
:
$ python2Python 2.7.3(默认,2012 年 9 月 26 日,21:53:58)[GCC 4.7.2] 在 linux2 上输入帮助"、版权"、信用"或许可"以获取更多信息.>>>'一些字符串' % []回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中类型错误:并非所有参数都在字符串格式化期间转换
这大概说明上面的问题并不是这里唯一的问题.
查看源代码我同意,理论上,如果参数不是元组,则不会检查参数的数量,但这意味着 'some string' % 5->'some string'
而不是 TypeError
,所以该代码中肯定有一些可疑的东西.
>>> '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
I would expect both cases to raise a TypeError
, but this is not the case. Why not?
The Python documentation on this subject talks about strings, tuples and dictionaries, but says nothing about lists. I'm a bit confused about this behavior. I've been able to duplicate it in Python 2.7 and 3.2.
Reading carefully, the documentation states that:
If format requires a single argument, values may be a single non-
tuple
object. Otherwise, values must be atuple
with exactly the number of items specified by the format string, or a single mapping object (for example, a dictionary).
Now, in this case the format
does not require a single argument and thus the documentation tells us that you should use a tuple
or a mapping as argument; other cases fall in "undefined behaviour"(which is what is happening: the behaviour is not consistent in all cases).
This should probably be considered the final answer to the question: if the string does not have any format specifier, using a list
(or any kind different from tuple
or a mapping) should simply be considered a bug by itself leading to undefined behaviour.
From this follows that you ought to always use a tuple
or dict
as argument, otherwise you have to check for format specifiers by hand or handle odd behaviours.
In your case you can probably fix the problem using (['string'], )
instead of ['string']
.
Possible "explanation" of why the resultant behaviour seems to be so random:
It seems like there was a buggy check in the original implementation of PyString_Format
/PyUnicode_Format
, instead of using PyMappingCheck
on this line:
if (PyMapping_Check(args) && !PyTuple_Check(args) &&
!PyObject_TypeCheck(args, &PyBaseString_Type))
dict = args;
It was used this code:
if (Py_TYPE(args)->tp_as_mapping && !PyTuple_Check(args) &&
!PyObject_TypeCheck(args, &PyBaseString_Type))
dict = args;
which is not equivalent. For example set
does not have tp_as_mapping
set(at least in the Python2.7.3 source code that I have downloaded some weeks ago), while list
does set it.
This might be the reason why list
(and possibly other objects) do not raise the TypeError
while, set
, int
and many others do.
As I stated before in this same answer I do get TypeError
even with list
s:
$ 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.
这篇关于为什么使用列表作为字符串格式化参数,即使没有 %s 标识符,也会返回原始字符串?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!