【问题标题】:How does CPython determine whether a user supplied an optional argument?CPython 如何确定用户是否提供了可选参数?
【发布时间】:2019-11-29 10:45:49
【问题描述】:

我开始想知道 CPython 如何区分 None 作为默认参数和 None 作为指定参数。

例如,如果密钥不存在,dict.pop() 将抛出 KeyError.pop() 还接受默认返回值的参数。在本例中,我们可以将默认返回设置为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 解决了用户是否提供了默认值的问题。这里的执行路径是什么?

【问题讨论】:

    标签: python python-internals


    【解决方案1】:

    如果没有传递第二个参数,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 的代码,如果参数元组不包含该参数的值,则生成的代码将为default_value 传递一个空指针。

    【讨论】:

    • (用python逻辑思考)空指针技巧只能用最后一个位置参数来完成,对吧?否则,我看不出这是如何工作的
    • @roganjosh:不,我不知道你是怎么想到它会被限制在最后一个位置参数的。
    • 从那以后你已经编辑过,现在它更有意义了。为了解释我对上一条评论 def x(a, b, c) 的逻辑并且您提供了 2 个位置参数,不清楚您是否为 b 提供了值
    • @roganjosh:可以在 Argument Clinic 中使用空默认值,任何可以使用非空默认值的地方。
    • 既然您已经显示默认值是在其他地方定义的,我的观点没有实际意义,而且我的想法显然不正确。感谢您的澄清:)
    猜你喜欢
    • 2010-12-12
    • 1970-01-01
    • 2018-07-28
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-14
    相关资源
    最近更新 更多