@@ -3037,9 +3037,8 @@ the class method :meth:`~object.__class_getitem__` may be called instead.
30373037object if it is properly defined.
30383038
30393039Presented 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
30673082In Python, all classes are themselves instances of other classes. The class of
30683083a class is known as that class's :term: `metaclass `, and most classes have the
0 commit comments