@@ -709,15 +709,17 @@ match_class_attr(PyThreadState *tstate, PyObject *subject, PyObject *type,
709709 PyObject * name , PyObject * seen )
710710{
711711 assert (PyUnicode_CheckExact (name ));
712- assert (PySet_CheckExact (seen ));
713- if (PySet_Contains (seen , name ) || PySet_Add (seen , name )) {
714- if (!_PyErr_Occurred (tstate )) {
715- // Seen it before!
716- _PyErr_Format (tstate , PyExc_TypeError ,
717- "%s() got multiple sub-patterns for attribute %R" ,
718- ((PyTypeObject * )type )-> tp_name , name );
712+ if (seen != NULL ) {
713+ assert (PySet_CheckExact (seen ));
714+ if (PySet_Contains (seen , name ) || PySet_Add (seen , name )) {
715+ if (!_PyErr_Occurred (tstate )) {
716+ // Seen it before!
717+ _PyErr_Format (tstate , PyExc_TypeError ,
718+ "%s() got multiple sub-patterns for attribute %R" ,
719+ ((PyTypeObject * )type )-> tp_name , name );
720+ }
721+ return NULL ;
719722 }
720- return NULL ;
721723 }
722724 PyObject * attr ;
723725 (void )PyObject_GetOptionalAttr (subject , name , & attr );
@@ -740,14 +742,24 @@ _PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type,
740742 if (PyObject_IsInstance (subject , type ) <= 0 ) {
741743 return NULL ;
742744 }
745+ // Short circuit if there aren't any arguments:
746+ Py_ssize_t nkwargs = PyTuple_GET_SIZE (kwargs );
747+ Py_ssize_clean_t nattrs = nargs + nkwargs ;
748+ if (!nattrs ) {
749+ PyObject * attrs = PyTuple_New (0 );
750+ return attrs ;
751+ }
743752 // So far so good:
744- PyObject * seen = PySet_New (NULL );
745- if (seen == NULL ) {
746- return NULL ;
753+ PyObject * seen = NULL ;
754+ if (nattrs > 1 ) {
755+ seen = PySet_New (NULL );
756+ if (seen == NULL ) {
757+ return NULL ;
758+ }
747759 }
748- PyObject * attrs = PyList_New ( 0 );
760+ PyObject * attrs = PyTuple_New ( nattrs );
749761 if (attrs == NULL ) {
750- Py_DECREF (seen );
762+ Py_XDECREF (seen );
751763 return NULL ;
752764 }
753765 // NOTE: From this point on, goto fail on failure:
@@ -788,9 +800,7 @@ _PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type,
788800 }
789801 if (match_self ) {
790802 // Easy. Copy the subject itself, and move on to kwargs.
791- if (PyList_Append (attrs , subject ) < 0 ) {
792- goto fail ;
793- }
803+ PyTuple_SET_ITEM (attrs , 0 , subject );
794804 }
795805 else {
796806 for (Py_ssize_t i = 0 ; i < nargs ; i ++ ) {
@@ -806,36 +816,27 @@ _PyEval_MatchClass(PyThreadState *tstate, PyObject *subject, PyObject *type,
806816 if (attr == NULL ) {
807817 goto fail ;
808818 }
809- if (PyList_Append (attrs , attr ) < 0 ) {
810- Py_DECREF (attr );
811- goto fail ;
812- }
813- Py_DECREF (attr );
819+ PyTuple_SET_ITEM (attrs , i , attr );
814820 }
815821 }
816822 Py_CLEAR (match_args );
817823 }
818824 // Finally, the keyword subpatterns:
819- for (Py_ssize_t i = 0 ; i < PyTuple_GET_SIZE ( kwargs ) ; i ++ ) {
825+ for (Py_ssize_t i = 0 ; i < nkwargs ; i ++ ) {
820826 PyObject * name = PyTuple_GET_ITEM (kwargs , i );
821827 PyObject * attr = match_class_attr (tstate , subject , type , name , seen );
822828 if (attr == NULL ) {
823829 goto fail ;
824830 }
825- if (PyList_Append (attrs , attr ) < 0 ) {
826- Py_DECREF (attr );
827- goto fail ;
828- }
829- Py_DECREF (attr );
831+ PyTuple_SET_ITEM (attrs , nargs + i , attr );
830832 }
831- Py_SETREF (attrs , PyList_AsTuple (attrs ));
832- Py_DECREF (seen );
833+ Py_XDECREF (seen );
833834 return attrs ;
834835fail :
835836 // We really don't care whether an error was raised or not... that's our
836837 // caller's problem. All we know is that the match failed.
837838 Py_XDECREF (match_args );
838- Py_DECREF (seen );
839+ Py_XDECREF (seen );
839840 Py_DECREF (attrs );
840841 return NULL ;
841842}
0 commit comments