gh-141980: Add attribute-based fallback for obj[key] when no mapping or sequence slot is defined
#141981
+64
−11
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR introduces an attribute-based fallback for the subscript operator (
obj[key]) when a type does not implement a mapping (tp_as_mapping->mp_subscript) or sequence (tp_as_sequence->sq_item) slot.related to: issue-141980
related to (same as issue): discuss
Problem
Currently, Python only allows
obj[key]if the type provides a C-level mapping or sequence slot. This means that objects implementing__getitem__purely through attribute resolution—such as through__getattr__, delegation, proxies, or wrapper objects—cannot support subscripting even though they logically provide the method.A simple example using a proxy-like object:
The proxy delegates all attribute lookups to
Config, including__getitem__, butcfg["x"]still raisesTypeErrorbecause Python never attempts attribute-based resolution for subscripting.This behavior is inconsistent with many other special methods, which already fall back to attribute resolution when a slot is not defined.
Proposed Solution
If the type does not define either:
tp_as_mapping->mp_subscript, ortp_as_sequence->sq_itemthen
obj[key]will now perform an attribute lookup for__getitem__using Python’s normal attribute resolution rules (__getattribute__,__getattr__, delegation, descriptors, etc.).If found and callable, it is invoked as:
If not found or not callable, the existing
TypeErrorbehavior is preserved.This is a strictly additive and backward-compatible enhancement.
Tests Added
A new test suite validates the fallback behavior using a proxy-style example:
Additional tests verify:
__getitem____getattr__Documentation
The data model documentation (
Doc/reference/datamodel.rst) is updated to reflect that:__getitem__as an attribute.NEWS Entry
Added under:
Contents:
Advantages
This change improves the expressiveness and flexibility of Python’s object model by allowing objects to participate in subscripting through normal attribute-resolution mechanisms. It becomes much easier to implement proxy, wrapper, or delegation patterns—mapping an object’s behavior to another object—without needing to define a C-level mapping slot. Any class that logically provides
__getitem__through__getattr__, or via dynamic delegation, can now supportobj[key]in a natural and predictable way.Importantly, the feature is strictly additive and does not alter the behavior of any existing code. Types that already define a mapping or sequence slot continue to use them with full precedence. Code that relies on TypeError for detecting subscriptability is unaffected, because the fallback is only considered for types that would otherwise raise the same TypeError.
Performance considerations
The performance impact is effectively negligible. In practical Python code, it is extremely rare for
TypeError: 'X' object is not subscriptableto be intentionally raised or used as part of a hot-path control flow. Outside of debugging scenarios, this error is almost never intentionally triggered.The fallback only executes in the exact situation where a TypeError would have been raised anyway, and attribute lookup is already a highly optimized operation in CPython. As a result, typical workloads will not experience any measurable slowdown, and no existing high-performance paths (such as list or dict subscripting) are affected at all.
Overall assessment
This enhancement provides a clear benefit—expanded flexibility and better alignment with Python’s dynamic attribute model—while introducing almost no downside. It preserves full backward compatibility, maintains existing precedence rules, and avoids affecting any commonly executed performance-critical code paths. As such, the change offers meaningful expressive power with minimal cost.
obj[key]to fallback to attribute-based__getitem__#141980📚 Documentation preview 📚: https://cpython-previews--141981.org.readthedocs.build/