Skip to content

gh-156250: Speed up inherited mapping assignment slot calls - #156258

Open
koxudaxi wants to merge 2 commits into
python:mainfrom
koxudaxi:perf/gh-156250-mapping-assignment-slot
Open

gh-156250: Speed up inherited mapping assignment slot calls#156258
koxudaxi wants to merge 2 commits into
python:mainfrom
koxudaxi:perf/gh-156250-mapping-assignment-slot

Conversation

@koxudaxi

@koxudaxi koxudaxi commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

__setitem__ and __delitem__ share the mp_ass_subscript slot. If a Python subclass of a C type overrides only one of them, the inherited operation is still dispatched through slot_mp_ass_subscript() and called through a wrapper_descriptor.

When lookup returns the expected unbound wrapper descriptor, slot_mp_ass_subscript() now calls the wrapped C slot directly. Python overrides and other descriptors continue through the generic call path.

Benchmark

I found this while profiling Counter-heavy code in a private project. Counter overrides __delitem__ but inherits dict.__setitem__, so several Counter operations go through this path.

I compared the feature commit 8ca6cd042b1e1fe91e2751c5abf3204631c749c0 with its direct parent b062727097e997bcb900e11503d3248daac903da. Both were release builds on macOS 15.7.1 arm64 with the same PGO/LTO configuration.

Operation Improvement
c[key] = value 49.9%
c[key] += 1 39.0%
c.update(mapping) 41.2%
c.subtract(mapping) 37.7%
a + b 28.7%
a | b 28.2%

Counter(iterable) and Counter.update(iterable) are not affected. They already use the _count_elements() C fast path.

I also checked larger workloads with the same two builds. NetworkX nx.triangles() was 5.1% to 9.0% faster across four graph shapes. The BPE benchmark in pyperformance was 6% to 8% faster in repeated runs.

The same one sided __setitem__ / __delitem__ pattern also exists outside Counter, but most of the other workloads I checked showed little or no end to end difference.

Given these results, I think this optimization is worth the extra complexity in slot_mp_ass_subscript(). The affected pattern is fairly narrow, but the improvement shows up in normal Counter operations and in larger workloads.

(Updated on August 26, 2026 with additional Counter and real world benchmark results.)

Tests

Tests cover asymmetric dict subclasses, inherited slice deletion on a list subclass, and fallback for custom or incompatible descriptors. The targeted tests pass on regular and free-threaded debug builds.

Fixes #156250

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve performance of inherited mapping assignment slot calls

1 participant