通过挖掘源代码可以找到答案。
尝试将非映射对象与 一起使用时**
,会出现以下错误:
TypeError: 'Foo' object is not a mapping
如果我们在 CPython 的源代码中搜索该错误,我们可以找到导致该错误发生的代码:
case TARGET(DICT_UPDATE): {
PyObject *update = POP();
PyObject *dict = PEEK(oparg);
if (PyDict_Update(dict, update) < 0) {
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Format(tstate, PyExc_TypeError,
"'%.200s' object is not a mapping",
Py_TYPE(update)->tp_name);
PyDict_Update
实际上是dict_merge
dict_merge
,返回负数时会抛出错误。如果我们检查 的来源dict_merge
,我们可以看到导致返回 -1 的原因:
/* We accept for the argument either a concrete dictionary object,
* or an abstract "mapping" object. For the former, we can do
* things quite efficiently. For the latter, we only require that
* PyMapping_Keys() and PyObject_GetItem() be supported.
*/
if (a == NULL || !PyDict_Check(a) || b == NULL) {
PyErr_BadInternalCall();
return -1;
关键部分是:
对于后者,我们只要求支持 PyMapping_Keys() 和 PyObject_GetItem()。