Skip to content

Commit e6497fe

Browse files
authored
bpo-45045: Optimize mapping patterns of structural pattern matching (GH-28043)
1 parent 94b2639 commit e6497fe

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

Lib/test/test_patma.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2641,6 +2641,19 @@ def f(x):
26412641
self.assertEqual(f((False, range(-1, -11, -1), True)), alts[3])
26422642
self.assertEqual(f((False, range(10, 20), True)), alts[4])
26432643

2644+
def test_patma_248(self):
2645+
class C(dict):
2646+
@staticmethod
2647+
def get(key, default=None):
2648+
return 'bar'
2649+
2650+
x = C({'foo': 'bar'})
2651+
match x:
2652+
case {'foo': bar}:
2653+
y = bar
2654+
2655+
self.assertEqual(y, 'bar')
2656+
26442657

26452658
class TestSyntaxErrors(unittest.TestCase):
26462659

Python/ceval.c

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -841,12 +841,18 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys)
841841
PyObject *seen = NULL;
842842
PyObject *dummy = NULL;
843843
PyObject *values = NULL;
844+
PyObject *get_name = NULL;
845+
PyObject *get = NULL;
844846
// We use the two argument form of map.get(key, default) for two reasons:
845847
// - Atomically check for a key and get its value without error handling.
846848
// - Don't cause key creation or resizing in dict subclasses like
847849
// collections.defaultdict that define __missing__ (or similar).
848850
_Py_IDENTIFIER(get);
849-
PyObject *get = _PyObject_GetAttrId(map, &PyId_get);
851+
get_name = _PyUnicode_FromId(&PyId_get); // borrowed
852+
if (get_name == NULL) {
853+
return NULL;
854+
}
855+
int meth_found = _PyObject_GetMethod(map, get_name, &get);
850856
if (get == NULL) {
851857
goto fail;
852858
}
@@ -859,7 +865,7 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys)
859865
if (dummy == NULL) {
860866
goto fail;
861867
}
862-
values = PyList_New(0);
868+
values = PyTuple_New(nkeys);
863869
if (values == NULL) {
864870
goto fail;
865871
}
@@ -873,7 +879,14 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys)
873879
}
874880
goto fail;
875881
}
876-
PyObject *value = PyObject_CallFunctionObjArgs(get, key, dummy, NULL);
882+
PyObject *args[] = { map, key, dummy };
883+
PyObject *value = NULL;
884+
if (meth_found) {
885+
value = PyObject_Vectorcall(get, args, 3, NULL);
886+
}
887+
else {
888+
value = PyObject_Vectorcall(get, &args[1], 2, NULL);
889+
}
877890
if (value == NULL) {
878891
goto fail;
879892
}
@@ -886,10 +899,8 @@ match_keys(PyThreadState *tstate, PyObject *map, PyObject *keys)
886899
values = Py_None;
887900
goto done;
888901
}
889-
PyList_Append(values, value);
890-
Py_DECREF(value);
902+
PyTuple_SET_ITEM(values, i, value);
891903
}
892-
Py_SETREF(values, PyList_AsTuple(values));
893904
// Success:
894905
done:
895906
Py_DECREF(get);

0 commit comments

Comments
 (0)