Uh oh!
There was an error while loading. Please reload this page.
gh-111262: Add PyDict_Pop() function [without default value nor KeyError] - #112028
Conversation
vstinner
commented
Nov 13, 2023
vstinner
commented
Nov 13, 2023
Simplified example where staticintsys_set_object(PyInterpreterState*interp, PyObject*key, PyObject*v)
{
PyObject*sd=interp->sysdict;
if (v==NULL) {
if (PyDict_Pop(sd, key, NULL) <0) {
return-1;
}
// no need to care about KeyError or Py_DECREF()return0;
}
else {
returnPyDict_SetItem(sd, key, v);
}
}Example which uses the removed value: PyObject*ob;
if (PyDict_Pop(kwargs, key, &ob) <0) {
goto error;
}
if (ob!=NULL) {
result->ob_item[i] =ob;
}
else {
// no need to care about KeyError or Py_DECREF()result->ob_item[i] =Py_NewRef(self->ob_item[i]);
} |
vstinner
commented
Nov 13, 2023
The function is not added to the limited C API: @encukouasks to wait until Python will have a C API Working Group. |
serhiy-storchaka
left a comment
There was a problem hiding this comment.
This PR includes yet one change. It allows to pass NULL as a result address. It complicates the implementation, but makes the common use case simpler.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| PyObject * | ||
| _PyDict_Pop(PyObject *dict, PyObject *key, PyObject *default_value) |
There was a problem hiding this comment.
I prefer to remove it in a separated PR: see #112026
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
| return NULL; | ||
| } | ||
| if (result == NULL) { | ||
| result = Py_NewRef(Py_None); |
There was a problem hiding this comment.
| result=Py_NewRef(Py_None); | |
| returnPyLong_FromLong(res); |
There was a problem hiding this comment.
I prefer to return (0, None) to make the tests written in Python closer to what the C API returns. In test_capi.test_dict, you can see that as (0, NULL).
There was a problem hiding this comment.
It can be confused with actual None. For example dict.get() return an actual none, but several corresponding C API functions return NULL.
In other tests I made them returning AttributeError or KeyError, as it is less chance to confuse with real value, but I think that it would be better to use a special singleton _testcapi.MISSING in future.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
vstinner
commented
Nov 13, 2023
As requested, I added I added tests on PyDict_PopString() and I also addresssed @serhiy-storchaka's review. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
vstinner
commented
Nov 13, 2023
@serhiy-storchaka: I added more tests. |
scoder
left a comment
There was a problem hiding this comment.
LGTM overall, just wording fixes.
| * Add :c:func:`PyDict_Pop` and :c:func:`PyDict_PopString` functions: remove a | ||
| key from a dictionary and optionally return the removed value. This is the | ||
| similar to :meth:`dict.pop`, but without the default value and do not raise | ||
| :exc:`KeyError` if the key missing. |
There was a problem hiding this comment.
It's usually clearer to write "not raising an exception" (at all) than naming an explicit exception and leaving it open whether other exceptions might be raised in the described case.
| * Add :c:func:`PyDict_Pop` and :c:func:`PyDict_PopString` functions: remove a | |
| key from a dictionary and optionally return the removed value. This is the | |
| similar to :meth:`dict.pop`, but without the default value and do not raise | |
| :exc:`KeyError` if the key missing. | |
| * Add :c:func:`PyDict_Pop` and :c:func:`PyDict_PopString` functions: remove a | |
| key from a dictionary and optionally return the removed value. This is | |
| similar to :meth:`dict.pop`, but without the default value and not raising | |
| an exception if the key missing. |
There was a problem hiding this comment.
Thanks. I applied your suggestion to the 3 places where I wrote that doc, but I kept KeyError. IMO it's useful to be explicit about KeyError to understand what we are talking about.
Uh oh!
There was an error while loading. Please reload this page.
vstinner
commented
Nov 14, 2023
At the beginning, I had no idea. It was very blurry. What helped me to make my own opinion was to actually use the different proposed API and look at the updated code. I really like this API without the default value: I'm convinced by these examples. In short, I prefer this PR. |
_PyDict_Pop_KnownHash(): remove the default value and the return type becomes an int. Co-Authored-By: Stefan Behnel <stefan_ml@behnel.de> Co-authored-by: Antoine Pitrou <pitrou@free.fr>
_PyDict_Pop_KnownHash(): remove the default value and the return type becomes an int. Co-authored-by: Stefan Behnel <stefan_ml@behnel.de> Co-authored-by: Antoine Pitrou <pitrou@free.fr>
_PyDict_Pop_KnownHash(): remove the default value and the return type becomes an int. Co-authored-by: Stefan Behnel <stefan_ml@behnel.de> Co-authored-by: Antoine Pitrou <pitrou@free.fr>
_PyDict_Pop_KnownHash(): remove the default value and the return type becomes an int.
📚 Documentation preview 📚: https://cpython-previews--112028.org.readthedocs.build/