diff options
author | Dong-hee Na <donghee.na@python.org> | 2021-08-30 10:02:32 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-30 10:02:32 (GMT) |
commit | e6497fe698f6e87344501a68ffdea106eafcb257 (patch) | |
tree | 718e80e25ac74a37c9f202930fa0171b7e2d8509 | |
parent | 94b2639fad50d7ff8acd12c11e5fe5f9a6e1da5c (diff) | |
download | cpython-e6497fe698f6e87344501a68ffdea106eafcb257.zip cpython-e6497fe698f6e87344501a68ffdea106eafcb257.tar.gz cpython-e6497fe698f6e87344501a68ffdea106eafcb257.tar.bz2 |
bpo-45045: Optimize mapping patterns of structural pattern matching (GH-28043)
-rw-r--r-- | Lib/test/test_patma.py | 13 | ||||
-rw-r--r-- | Python/ceval.c | 23 |
2 files changed, 30 insertions, 6 deletions
diff --git a/Lib/test/test_patma.py b/Lib/test/test_patma.py index aa18e29..57d3b1e 100644 --- a/Lib/test/test_patma.py +++ b/Lib/test/test_patma.py @@ -2641,6 +2641,19 @@ class TestPatma(unittest.TestCase): self.assertEqual(f((False, range(-1, -11, -1), True)), alts[3]) self.assertEqual(f((False, range(10, 20), True)), alts[4]) + def test_patma_248(self): + class C(dict): + @staticmethod + def get(key, default=None): + return 'bar' + + x = C({'foo': 'bar'}) + match x: + case {'foo': bar}: + y = bar + + self.assertEqual(y, 'bar') + class TestSyntaxErrors(unittest.TestCase): diff --git a/Python/ceval.c b/Python/ceval.c index 8aaa83b..bf95d50 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -841,12 +841,18 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) PyObject *seen = NULL; PyObject *dummy = NULL; PyObject *values = NULL; + PyObject *get_name = NULL; + PyObject *get = NULL; // We use the two argument form of map.get(key, default) for two reasons: // - Atomically check for a key and get its value without error handling. // - Don't cause key creation or resizing in dict subclasses like // collections.defaultdict that define __missing__ (or similar). _Py_IDENTIFIER(get); - PyObject *get = _PyObject_GetAttrId(map, &PyId_get); + get_name = _PyUnicode_FromId(&PyId_get); // borrowed + if (get_name == NULL) { + return NULL; + } + int meth_found = _PyObject_GetMethod(map, get_name, &get); if (get == NULL) { goto fail; } @@ -859,7 +865,7 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) if (dummy == NULL) { goto fail; } - values = PyList_New(0); + values = PyTuple_New(nkeys); if (values == NULL) { goto fail; } @@ -873,7 +879,14 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) } goto fail; } - PyObject *value = PyObject_CallFunctionObjArgs(get, key, dummy, NULL); + PyObject *args[] = { map, key, dummy }; + PyObject *value = NULL; + if (meth_found) { + value = PyObject_Vectorcall(get, args, 3, NULL); + } + else { + value = PyObject_Vectorcall(get, &args[1], 2, NULL); + } if (value == NULL) { goto fail; } @@ -886,10 +899,8 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys) values = Py_None; goto done; } - PyList_Append(values, value); - Py_DECREF(value); + PyTuple_SET_ITEM(values, i, value); } - Py_SETREF(values, PyList_AsTuple(values)); // Success: done: Py_DECREF(get); |