是否已记录str.__mod__
的确切行为?
这两行代码按预期工作:
>>> 'My number is: %s.' % 123
'My number is: 123.'
>>> 'My list is: %s.' % [1, 2, 3]
'My list is: [1, 2, 3].'
此行的行为也符合预期:
>>> 'Not a format string' % 123
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting
但是这行是什么以及为什么它不会引发任何错误?
>>> 'Not a format string' % [1, 2, 3]
'Not a format string'
P。 S。
>>> print(sys.version)
3.3.2 (default, Aug 15 2013, 23:43:52)
[GCC 4.7.3]
添加了最新的printf样式格式后,%
格式似乎出现了一些小怪癖。今天(版本3.8)为documented here,但在版本3.3 here中已提及。
这里描述的格式化操作表现出各种怪癖导致许多常见错误(例如无法显示元组和字典正确)。使用较新的格式化字符串文字,
str.format()
接口或模板字符串可能会有所帮助避免这些错误。这些替代方案各自提供自己的权衡取舍和简单性,灵活性和/或好处可扩展性。
[在此特定情况下,Python在__getitem__
的右侧使用%
方法看到了非元组值,并假定必须完成format_map
。通常使用format_map
完成此操作,但实际上可以使用dict
方法处理任何对象。
尤其是,允许__getitem__
忽略未使用的键,因为您通常不对映射项进行迭代来访问它们。
format_map
您的示例是该功能的使用,其中容器的所有键均被忽略。
>>> "Include those items: %(foo)s %(bar)s" % {"foo": 1, "bar": 2, "ignored": 3}
'Include those items: 1 2'
如果要进一步证明这一点,请检查将>>> "Include no items:" % {"foo": 1, "bar": 2}
'Include no items:'
用作右侧时会发生什么。
list
Python确实尝试获取>>> lst = ["foo", "bar", "baz"]
>>> "Include those items: %(0)s, %(2)s" % lst
TypeError: list indices must be integers or slices, not str
,不幸的是,没有办法指定应将lst["0"]
转换为"0"
,因此注定要以int
语法失败。
我认为可以在CPython源代码中找到负责的行,我得到了git %
:
[v3.8.2
,第15008行
Objects/unicodeobject.c
如果if (ctx.argidx < ctx.arglen && !ctx.dict) {
PyErr_SetString(PyExc_TypeError,
"not all arguments converted during string formatting");
goto onError;
}
不匹配,将产生错误,但如果arglen
为真,将不产生错误。什么时候是真的?:
[!ctx.dict
,第14976行
Objects/unicodeobject.c
[确定,if (PyMapping_Check(args) && !PyTuple_Check(args) && !PyUnicode_Check(args))
ctx.dict = args;
else
ctx.dict = NULL;
检查传递的PyMapping_Check
,如果它是args
,并且我们没有设置为1
的元组或Unicode字符串。
ctx.dict
做什么?
[PyMapping_Check
,第2110行
Objects/abstract.c
根据我的理解,如果该对象可以用作“映射”,或者可以被索引/下标,则将返回int
PyMapping_Check(PyObject *o)
{
return o && o->ob_type->tp_as_mapping &&
o->ob_type->tp_as_mapping->mp_subscript;
}
。在这种情况下,1
的值将设置为ctx.dict
,即args
,因此不会进入错误情况。 !NULL
和dict
都可以用作此类映射。在第14976行的检查中明确禁止list
(因为它用于将可变参数传递给格式化程序)。
不过,我不清楚这种行为是故意还是出于故意的原因。