[Python-checkins] bpo-37151: simplify classmethoddescr_call (GH-13340)

Petr Viktorin webhook-mailer at python.org
Fri Jun 7 06:20:39 EDT 2019


https://github.com/python/cpython/commit/3f345c39255dc3823dd989d4e3c93b12d18c44e0
commit: 3f345c39255dc3823dd989d4e3c93b12d18c44e0
branch: master
author: Jeroen Demeyer <J.Demeyer at UGent.be>
committer: Petr Viktorin <encukou at gmail.com>
date: 2019-06-07T12:20:23+02:00
summary:

bpo-37151: simplify classmethoddescr_call (GH-13340)

files:
M Lib/test/test_descr.py
M Objects/descrobject.c

diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 6b018ccc56fa..301a2d2a0fd2 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -1613,8 +1613,8 @@ class SubSpam(spam.spamlist): pass
             spam_cm(spam.spamlist())
         self.assertEqual(
             str(cm.exception),
-            "descriptor 'classmeth' requires a type "
-            "but received a 'xxsubtype.spamlist' instance")
+            "descriptor 'classmeth' for type 'xxsubtype.spamlist' "
+            "needs a type, not a 'xxsubtype.spamlist' as arg 2")
 
         with self.assertRaises(TypeError) as cm:
             spam_cm(list)
diff --git a/Objects/descrobject.c b/Objects/descrobject.c
index 6c95a8726c42..806c0af97e24 100644
--- a/Objects/descrobject.c
+++ b/Objects/descrobject.c
@@ -300,16 +300,19 @@ _PyMethodDescr_Vectorcall(PyObject *descrobj,
     return result;
 }
 
+/* Instances of classmethod_descriptor are unlikely to be called directly.
+   For one, the analogous class "classmethod" (for Python classes) is not
+   callable. Second, users are not likely to access a classmethod_descriptor
+   directly, since it means pulling it from the class __dict__.
+
+   This is just an excuse to say that this doesn't need to be optimized:
+   we implement this simply by calling __get__ and then calling the result.
+*/
 static PyObject *
 classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
                       PyObject *kwds)
 {
-    Py_ssize_t argc;
-    PyObject *self, *result;
-
-    /* Make sure that the first argument is acceptable as 'self' */
-    assert(PyTuple_Check(args));
-    argc = PyTuple_GET_SIZE(args);
+    Py_ssize_t argc = PyTuple_GET_SIZE(args);
     if (argc < 1) {
         PyErr_Format(PyExc_TypeError,
                      "descriptor '%V' of '%.100s' "
@@ -318,30 +321,15 @@ classmethoddescr_call(PyMethodDescrObject *descr, PyObject *args,
                      PyDescr_TYPE(descr)->tp_name);
         return NULL;
     }
-    self = PyTuple_GET_ITEM(args, 0);
-    if (!PyType_Check(self)) {
-        PyErr_Format(PyExc_TypeError,
-                     "descriptor '%V' requires a type "
-                     "but received a '%.100s' instance",
-                     descr_name((PyDescrObject *)descr), "?",
-                     self->ob_type->tp_name);
-        return NULL;
-    }
-    if (!PyType_IsSubtype((PyTypeObject *)self, PyDescr_TYPE(descr))) {
-        PyErr_Format(PyExc_TypeError,
-                     "descriptor '%V' requires a subtype of '%.100s' "
-                     "but received '%.100s'",
-                     descr_name((PyDescrObject *)descr), "?",
-                     PyDescr_TYPE(descr)->tp_name,
-                     ((PyTypeObject*)self)->tp_name);
+    PyObject *self = PyTuple_GET_ITEM(args, 0);
+    PyObject *bound = classmethod_get(descr, NULL, self);
+    if (bound == NULL) {
         return NULL;
     }
-
-    result = _PyMethodDef_RawFastCallDict(descr->d_method, self,
-                                          &_PyTuple_ITEMS(args)[1], argc - 1,
-                                          kwds);
-    result = _Py_CheckFunctionResult((PyObject *)descr, result, NULL);
-    return result;
+    PyObject *res = _PyObject_FastCallDict(bound, _PyTuple_ITEMS(args)+1,
+                                           argc-1, kwds);
+    Py_DECREF(bound);
+    return res;
 }
 
 Py_LOCAL_INLINE(PyObject *)



More information about the Python-checkins mailing list