Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 64156) +++ Python/ceval.c (working copy) @@ -2753,6 +2753,7 @@ } } for (i = 0; i < kwcount; i++) { + PyObject **co_varnames; PyObject *keyword = kws[2*i]; PyObject *value = kws[2*i + 1]; int j; @@ -2762,14 +2763,20 @@ PyString_AsString(co->co_name)); goto fail; } - /* XXX slow -- speed up using dictionary? */ + /* Speed hack: do raw pointer compares. As names are + normally interned this should almost always hit. */ + co_varnames = PySequence_Fast_ITEMS(co->co_varnames); for (j = 0; j < co->co_argcount; j++) { - PyObject *nm = PyTuple_GET_ITEM( - co->co_varnames, j); - int cmp = PyObject_RichCompareBool( - keyword, nm, Py_EQ); + PyObject *nm = co_varnames[j]; + if (nm == keyword) + goto kw_found; + } + /* Slow fallback, just in case */ + for (j = 0; j < co->co_argcount; j++) { + PyObject *nm = co_varnames[j]; + int cmp = PyObject_RichCompareBool(keyword, nm, Py_EQ); if (cmp > 0) - break; + goto kw_found; else if (cmp < 0) goto fail; } @@ -2786,20 +2793,20 @@ goto fail; } PyDict_SetItem(kwdict, keyword, value); + continue; } - else { - if (GETLOCAL(j) != NULL) { - PyErr_Format(PyExc_TypeError, - "%.200s() got multiple " - "values for keyword " - "argument '%.400s'", - PyString_AsString(co->co_name), - PyString_AsString(keyword)); - goto fail; - } - Py_INCREF(value); - SETLOCAL(j, value); +kw_found: + if (GETLOCAL(j) != NULL) { + PyErr_Format(PyExc_TypeError, + "%.200s() got multiple " + "values for keyword " + "argument '%.400s'", + PyString_AsString(co->co_name), + PyString_AsString(keyword)); + goto fail; } + Py_INCREF(value); + SETLOCAL(j, value); } if (argcount < co->co_argcount) { int m = co->co_argcount - defcount;