GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing github.com — gh-111262: Add PyDict_Pop() function [without default value nor KeyError] by vstinner · Pull Request #112028 · python/cpython Conversation
|
|
This PR is based on PR gh-111939 (which was based on PR gh-111263). This API is different:
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Simplified example where static int sys_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() return 0; } else { return PyDict_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]); } |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
The function is not added to the limited C API: @encukou asks to wait until Python will have a C API Working Group. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
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.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
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.
The reason will be displayed to describe this comment to others. Learn more.
Why not remove it?
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
I prefer to remove it in a separated PR: see #112026
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
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.
The reason will be displayed to describe this comment to others. Learn more.
| result = Py_NewRef(Py_None); | |
| return PyLong_FromLong(res); |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
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).
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
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.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
As requested, I added I added tests on PyDict_PopString() and I also addresssed @serhiy-storchaka's review. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
@serhiy-storchaka: I added more tests. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
LGTM overall, just wording fixes.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
| * 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.
The reason will be displayed to describe this comment to others. Learn more.
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. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
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.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
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. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
_PyDict_Pop_KnownHash(): remove the default value and the return type becomes an int. Co-Authored-By: Stefan Behnel <[email protected]> Co-authored-by: Antoine Pitrou <[email protected]>
_PyDict_Pop_KnownHash(): remove the default value and the return type becomes an int. Co-authored-by: Stefan Behnel <[email protected]> Co-authored-by: Antoine Pitrou <[email protected]>
_PyDict_Pop_KnownHash(): remove the default value and the return type becomes an int. Co-authored-by: Stefan Behnel <[email protected]> Co-authored-by: Antoine Pitrou <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.