为什么使用列表作为字符串格式化参数,即使没有 %s 标识符,也会返回原始字符串? [英] Why does using a list as a string formatting parameter, even with no %s identifier, return the original string?

查看:26
本文介绍了为什么使用列表作为字符串格式化参数,即使没有 %s 标识符,也会返回原始字符串?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

<预><代码>>>>'没有字符串格式标记的字符串' % ['string']'没有字符串格式标记的字符串'>>>'没有字符串格式标记的字符串' % ('string',)回溯(最近一次调用最后一次):文件<stdin>",第 1 行,在 <module> 中类型错误:并非所有参数都在字符串格式化期间转换

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

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

解决方案

仔细阅读,文档说明:

<块引用>

如果格式需要单个参数,则值可能是单个非元组目的.否则,值必须是一个 tuple 与数字由格式字符串或单个映射对象指定的项目(例如,字典).

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

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

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

在您的情况下,您可以使用 (['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 的原因 和许多其他人这样做.

正如我之前在同一个答案中所说的,即使使用 lists,我也会得到 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 a tuple 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 lists:

$ 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆