Skip to content

Commit 41bc293

Browse files
Refine subscription process explanation in docs
1 parent 7e5327e commit 41bc293

File tree

1 file changed

+26
-11
lines changed

1 file changed

+26
-11
lines changed

Doc/reference/datamodel.rst

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3037,9 +3037,8 @@ the class method :meth:`~object.__class_getitem__` may be called instead.
30373037
object if it is properly defined.
30383038

30393039
Presented with the :term:`expression` ``obj[x]``, the Python interpreter
3040-
follows something like the following process to decide whether
3041-
:meth:`~object.__getitem__` or :meth:`~object.__class_getitem__` should be
3042-
called::
3040+
follows a process similar to the following to determine which operation should
3041+
be used to perform the subscription::
30433042

30443043
from inspect import isclass
30453044

@@ -3048,21 +3047,37 @@ called::
30483047

30493048
class_of_obj = type(obj)
30503049

3051-
# If the class of obj defines __getitem__,
3052-
# call class_of_obj.__getitem__(obj, x)
3050+
# 1. If the class defines a mapping slot (__getitem__),
3051+
# call it directly.
30533052
if hasattr(class_of_obj, '__getitem__'):
30543053
return class_of_obj.__getitem__(obj, x)
30553054

3056-
# Else, if obj is a class and defines __class_getitem__,
3055+
# 2. If the class defines a sequence slot (sq_item)
3056+
# and the key is an integer, call sq_item.
3057+
if hasattr(class_of_obj, '__getitem__') is False:
3058+
# simplified model: CPython checks tp_as_sequence->sq_item
3059+
if isinstance(x, int) and hasattr(class_of_obj, '__len__'):
3060+
return obj.__getitem__(x)
3061+
3062+
# 3. If obj is a class and defines __class_getitem__,
30573063
# call obj.__class_getitem__(x)
3058-
elif isclass(obj) and hasattr(obj, '__class_getitem__'):
3064+
if isclass(obj) and hasattr(obj, '__class_getitem__'):
30593065
return obj.__class_getitem__(x)
30603066

3061-
# Else, raise an exception
3067+
# 4. Attribute-based fallback: if __getitem__ is provided
3068+
# by __getattribute__ or __getattr__, call it.
3069+
try:
3070+
attr_getitem = obj.__getattribute__('__getitem__')
3071+
except AttributeError:
3072+
pass
30623073
else:
3063-
raise TypeError(
3064-
f"'{class_of_obj.__name__}' object is not subscriptable"
3065-
)
3074+
if callable(attr_getitem):
3075+
return attr_getitem(x)
3076+
3077+
# 5. Otherwise, raise an exception.
3078+
raise TypeError(
3079+
f"'{class_of_obj.__name__}' object is not subscriptable"
3080+
)
30663081

30673082
In Python, all classes are themselves instances of other classes. The class of
30683083
a class is known as that class's :term:`metaclass`, and most classes have the

0 commit comments

Comments
 (0)