Python'string'%[1,2,3]不会引发TypeError

问题描述 投票:9回答:2

是否已记录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]
python list modulo string-interpolation python-3.2
2个回答
4
投票

添加了最新的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语法失败。


3
投票

我认为可以在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,因此不会进入错误情况。 !NULLdict都可以用作此类映射。在第14976行的检查中明确禁止list(因为它用于将可变参数传递给格式化程序)。

不过,我不清楚这种行为是故意还是出于故意的原因。

© www.soinside.com 2019 - 2024. All rights reserved.