CPython 如何确定用户是否提供了可选参数?
How does CPython determine whether a user supplied an optional argument?
我开始想知道 CPython 如何区分作为默认参数的 None
和作为指定参数的 None
之间的区别。
例如,如果密钥不存在,dict.pop()
将抛出 KeyError
。 .pop()
也接受默认 return 值的参数。在此示例中,我们可以将默认值 return 设置为 None
,因此:some_dict.pop(some_key, None)
如果您要在 Python 中定义 pop
,您可能会:
def pop(some_key, default=None):
在那种情况下,将 default
定义为 None
还是将其省略都没有什么区别,但是 Python 可以分辨出区别。我在 CPython 中做了一些挖掘,发现了 dict.pop()
:
的实现
PyObject *
_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
{
Py_hash_t hash;
if (((PyDictObject *)dict)->ma_used == 0) {
if (deflt) {
Py_INCREF(deflt);
return deflt;
}
_PyErr_SetKeyError(key);
return NULL;
}
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) {
hash = PyObject_Hash(key);
if (hash == -1)
return NULL;
}
return _PyDict_Pop_KnownHash(dict, key, hash, deflt);
}
我能大致理解它是如何工作的。但是,除了那个函数定义之外,我似乎找不到 deflt
(有人向我建议 CPython 有一个 None 的空指针,但我可能不认识它), 所以我不太明白 CPython 是如何解决用户是否提供默认值的问题的。这里的执行路径是什么?
如果没有传递第二个参数,deflt
是一个空指针,而不是指向 None
或任何其他 Python 对象。这不是用 Python.
编写的函数可以做的事情
您查看的函数未定义默认值。您正在查看中间辅助函数。默认值在 dict_pop_impl
:
旁边的 Argument Clinic 指令中指定
/*[clinic input]
dict.pop
key: object
default: object = NULL
/
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, default is returned if given, otherwise KeyError is raised
[clinic start generated code]*/
static PyObject *
dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
/*[clinic end generated code: output=3abb47b89f24c21c input=eeebec7812190348]*/
{
return _PyDict_Pop((PyObject*)self, key, default_value);
}
见default: object = NULL
。此注释经过预处理以生成查看 dict.pop
的参数元组并调用 dict_pop_impl
的代码,如果参数元组不包含该参数的值。
我开始想知道 CPython 如何区分作为默认参数的 None
和作为指定参数的 None
之间的区别。
例如,如果密钥不存在,dict.pop()
将抛出 KeyError
。 .pop()
也接受默认 return 值的参数。在此示例中,我们可以将默认值 return 设置为 None
,因此:some_dict.pop(some_key, None)
如果您要在 Python 中定义 pop
,您可能会:
def pop(some_key, default=None):
在那种情况下,将 default
定义为 None
还是将其省略都没有什么区别,但是 Python 可以分辨出区别。我在 CPython 中做了一些挖掘,发现了 dict.pop()
:
PyObject *
_PyDict_Pop(PyObject *dict, PyObject *key, PyObject *deflt)
{
Py_hash_t hash;
if (((PyDictObject *)dict)->ma_used == 0) {
if (deflt) {
Py_INCREF(deflt);
return deflt;
}
_PyErr_SetKeyError(key);
return NULL;
}
if (!PyUnicode_CheckExact(key) ||
(hash = ((PyASCIIObject *) key)->hash) == -1) {
hash = PyObject_Hash(key);
if (hash == -1)
return NULL;
}
return _PyDict_Pop_KnownHash(dict, key, hash, deflt);
}
我能大致理解它是如何工作的。但是,除了那个函数定义之外,我似乎找不到 deflt
(有人向我建议 CPython 有一个 None 的空指针,但我可能不认识它), 所以我不太明白 CPython 是如何解决用户是否提供默认值的问题的。这里的执行路径是什么?
如果没有传递第二个参数,deflt
是一个空指针,而不是指向 None
或任何其他 Python 对象。这不是用 Python.
您查看的函数未定义默认值。您正在查看中间辅助函数。默认值在 dict_pop_impl
:
/*[clinic input]
dict.pop
key: object
default: object = NULL
/
D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, default is returned if given, otherwise KeyError is raised
[clinic start generated code]*/
static PyObject *
dict_pop_impl(PyDictObject *self, PyObject *key, PyObject *default_value)
/*[clinic end generated code: output=3abb47b89f24c21c input=eeebec7812190348]*/
{
return _PyDict_Pop((PyObject*)self, key, default_value);
}
见default: object = NULL
。此注释经过预处理以生成查看 dict.pop
的参数元组并调用 dict_pop_impl
的代码,如果参数元组不包含该参数的值。