bpo-32226: Implementation of PEP 560 (core components)#4732
bpo-32226: Implementation of PEP 560 (core components)#4732ilevkivskyi merged 40 commits intopython:masterfrom
Conversation
|
@serhiy-storchaka Thank you very much for review! I will make the changes tomorrow. |
|
I have made the requested changes; please review again |
|
Thanks for making the requested changes! @serhiy-storchaka: please review the changes made to this pull request. |
|
@serhiy-storchaka Following your comment #4731 (comment) I also removed callability checks for special methods here. If you think it makes sense to customize error messages in future, then I can open a b.p.o. issue for this. |
|
(I will add documentation for this in a separate PR after the second part of changes -- changes to |
| goto error; | ||
| } | ||
| if (!replacements) { | ||
| replacements = PyTuple_New(nargs - 2); |
There was a problem hiding this comment.
Handle an error.
I suggest to use a list instead of a tuple. You can fill it at the single pass and convert to a tuple at end.
if (!new_bases) {
new_bases = PyList_New(i);
if (!new_bases) {
goto error;
}
// copy i items to new_bases
}
if (_PyList_Extend(new_bases, new_base) < 0) {
goto error;
}| replacements = NULL; | ||
| /* We have a separate cycle to calculate replacements with the idea that in | ||
| most cases we just scroll quickly though it and return original bases */ | ||
| for (i = 2; i < nargs; i++){ |
There was a problem hiding this comment.
I think the code would look simpler if pass nargs-2 and args+2. Or passing just bases may be enough.
Needed a space before {.
| Py_XDECREF(mkw); | ||
| Py_DECREF(bases); | ||
| if (modified_bases) { | ||
| Py_DECREF(old_bases); |
There was a problem hiding this comment.
Just
Py_XDECREF(old_bases);There was a problem hiding this comment.
This is not really possible, since this code is also executed on success, and in this case if there were no conversion, then bases should be DECREFed exactly once.
| return NULL; | ||
| } | ||
| else { | ||
| old_bases = bases; |
There was a problem hiding this comment.
The code would look simpler if set the original bases to orig_bases.
orig_bases = _PyStack_AsTupleSlice(...);
if (orig_bases == NULL)
return NULL;
bases = update_bases(...);
if (bases == NULL) {
Py_DECREF(orig_bases);
return NULL;
}| NULL, 0, NULL, 0, NULL, 0, NULL, | ||
| PyFunction_GET_CLOSURE(func)); | ||
| if (cell != NULL) { | ||
| if (modified_bases) { |
There was a problem hiding this comment.
if (bases != orig_bases) {modified_bases is not needed.
|
@serhiy-storchaka Thank you for another review! I converted the code to the single pass as you suggested. The code indeed looks cleaner, however performance is worse now. For normal (non-generic) classes there is slow-down of up to 5%. Do you have any ideas about how to boost performance here? |
|
@serhiy-storchaka Ah, sorry, I forgot to merge master before bechmarking. In fact, there are no visible slow-downs. (Which makes sense, since I just added few pointer comparisons.) |
| PyErr_Clear(); | ||
| if (new_bases) { | ||
| if (PyList_Append(new_bases, base) < 0) { | ||
| Py_DECREF(meth); |
| if (!new_base) { | ||
| goto error; | ||
| } | ||
| if (PyTuple_Check(new_base)) { |
There was a problem hiding this comment.
I suggest to swap branches and move the success branch to upper level. I think this will make the code clearer.
if (!PyTuple_Check(new_base)) {
...
goto error;
}
if (!new_bases) {
...| } | ||
| continue; | ||
| } | ||
| if (!(meth = _PyObject_GetAttrId(base, &PyId___mro_entries__))) { |
There was a problem hiding this comment.
It would look clearer if make an assignment on a separate line.
| PyObject *stack[1] = {bases}; | ||
| assert(PyTuple_Check(bases)); | ||
|
|
||
| /* We have a separate cycle to calculate replacements with the idea that in |
There was a problem hiding this comment.
Is this comment outdated?
|
|
||
| /* We have a separate cycle to calculate replacements with the idea that in | ||
| most cases we just scroll quickly though it and return original bases */ | ||
| for (i = 0; i < nargs; i++) { |
There was a problem hiding this comment.
For performance try to add a separate fast loop for non-generic types.
for (i = 0; i < nargs && PyType_Check(args[i]); i++) {
}
if (i == nargs) {
return bases;
}
new_bases = PyList_New(i);
...
for (; i < nargs; i++) {There was a problem hiding this comment.
This doesn't give any visible difference, so I will just keep the single loop (As I mentioned before, a more careful benchmark showed that it is already good).
| if (!new_bases) { | ||
| /* If this is a first successful conversion, create new_bases list and | ||
| copy previously encountered bases. */ | ||
| new_bases = PyList_New(i); |
| if (!_PyList_Extend((PyListObject *)new_bases, new_base)) { | ||
| goto error; | ||
| } | ||
| Py_DECREF(Py_None); |
There was a problem hiding this comment.
This looks confusing. Add a comment to this non-obvious code.
Alternatively you can use a public PyList_SetSlice instead of _PyList_Extend if you prefer.
j = PyList_GET_SIZE(new_bases);
if (PyList_SetSlice(new_bases, j, j, new_base) < 0) {
goto error;
}| #include "clinic/bltinmodule.c.h" | ||
|
|
||
| static PyObject* | ||
| update_bases(PyObject* bases, PyObject** args, int nargs) |
There was a problem hiding this comment.
Add the const qualifier. See bpo-32240.
It is more common to add a space before * instead of after it.
| result = PyList_AsTuple(new_bases); | ||
| Py_DECREF(new_bases); | ||
| return result; | ||
| error: |
There was a problem hiding this comment.
This is just my personal preference, but I prefer to add an empty line after return and before a label (closing brace can replace an empty line). This make the code cleaner to me.
|
@serhiy-storchaka Does this PR look OK to you now? (Taking into account that Guido likes the current implementation "strategy" of I am really sorry for constantly pushing you on this. There are few other things that depend on this PR |
serhiy-storchaka
left a comment
There was a problem hiding this comment.
LGTM. This introduces a small performance regression, but it can be be fixed later.
OK, thanks! Then I will merge this now. |
This is a basic implementation of the PEP. Suggestions are welcome.
@gvanrossum @serhiy-storchaka Can one of you (or both?) please review?
cc: @markshannon IIRC you are interested in implementation details of this PEP.
https://bugs.python.org/issue32226