@@ -2144,22 +2144,142 @@ case the instance is itself a class.
2144
2144
Emulating generic types
2145
2145
-----------------------
2146
2146
2147
- One can implement the generic class syntax as specified by :pep: `484 `
2148
- (for example ``List[int] ``) by defining a special method:
2147
+ When using :term: `type annotations<annotation> `, it is often useful to
2148
+ *parameterize * a :term: `generic type ` using Python's square-brackets notation.
2149
+ For example, the annotation ``list[int] `` might be used to signify a
2150
+ :class: `list ` in which all the elements are of type :class: `int `.
2151
+
2152
+ .. seealso ::
2153
+
2154
+ :pep: `484 ` - Type Hints
2155
+ Introducing Python's framework for type annotations
2156
+
2157
+ :ref: `Generic Alias Types<types-genericalias> `
2158
+ Documentation for objects representing parameterized generic classes
2159
+
2160
+ :ref: `Generics `, :ref: `user-defined generics<user-defined-generics> ` and :class: `typing.Generic `
2161
+ Documentation on how to implement generic classes that can be
2162
+ parameterized at runtime and understood by static type-checkers.
2163
+
2164
+ A class can *generally * only be parameterized if it defines the special
2165
+ class method ``__class_getitem__() ``.
2149
2166
2150
2167
.. classmethod :: object.__class_getitem__(cls, key)
2151
2168
2152
2169
Return an object representing the specialization of a generic class
2153
2170
by type arguments found in *key *.
2154
2171
2155
- This method is looked up on the class object itself, and when defined in
2156
- the class body, this method is implicitly a class method. Note, this
2157
- mechanism is primarily reserved for use with static type hints, other usage
2158
- is discouraged.
2172
+ When defined on a class, ``__class_getitem__() `` is automatically a class
2173
+ method. As such, there is no need for it to be decorated with
2174
+ :func: `@classmethod<classmethod> ` when it is defined.
2159
2175
2160
- .. seealso ::
2161
2176
2162
- :pep: `560 ` - Core support for typing module and generic types
2177
+ The purpose of *__class_getitem__ *
2178
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2179
+
2180
+ The purpose of :meth: `~object.__class_getitem__ ` is to allow runtime
2181
+ parameterization of standard-library generic classes in order to more easily
2182
+ apply :term: `type hints<type hint> ` to these classes.
2183
+
2184
+ To implement custom generic classes that can be parameterized at runtime and
2185
+ understood by static type-checkers, users should either inherit from a standard
2186
+ library class that already implements :meth: `~object.__class_getitem__ `, or
2187
+ inherit from :class: `typing.Generic `, which has its own implementation of
2188
+ ``__class_getitem__() ``.
2189
+
2190
+ Custom implementations of :meth: `~object.__class_getitem__ ` on classes defined
2191
+ outside of the standard library may not be understood by third-party
2192
+ type-checkers such as mypy. Using ``__class_getitem__() `` on any class for
2193
+ purposes other than type hinting is discouraged.
2194
+
2195
+
2196
+ .. _classgetitem-versus-getitem :
2197
+
2198
+
2199
+ *__class_getitem__ * versus *__getitem__ *
2200
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2201
+
2202
+ Usually, the :ref: `subscription<subscriptions> ` of an object using square
2203
+ brackets will call the :meth: `~object.__getitem__ ` instance method defined on
2204
+ the object's class. However, if the object being subscribed is itself a class,
2205
+ the class method :meth: `~object.__class_getitem__ ` may be called instead.
2206
+ ``__class_getitem__() `` should return a :ref: `GenericAlias<types-genericalias> `
2207
+ object if it is properly defined.
2208
+
2209
+ Presented with the :term: `expression ` ``obj[x] ``, the Python interpreter
2210
+ follows something like the following process to decide whether
2211
+ :meth: `~object.__getitem__ ` or :meth: `~object.__class_getitem__ ` should be
2212
+ called::
2213
+
2214
+ from inspect import isclass
2215
+
2216
+ def subscribe(obj, x):
2217
+ """Return the result of the expression `obj[x]`"""
2218
+
2219
+ class_of_obj = type(obj)
2220
+
2221
+ # If the class of obj defines __getitem__,
2222
+ # call class_of_obj.__getitem__(obj, x)
2223
+ if hasattr(class_of_obj, '__getitem__'):
2224
+ return class_of_obj.__getitem__(obj, x)
2225
+
2226
+ # Else, if obj is a class and defines __class_getitem__,
2227
+ # call obj.__class_getitem__(x)
2228
+ elif isclass(obj) and hasattr(obj, '__class_getitem__'):
2229
+ return obj.__class_getitem__(x)
2230
+
2231
+ # Else, raise an exception
2232
+ else:
2233
+ raise TypeError(
2234
+ f"'{class_of_obj.__name__}' object is not subscriptable"
2235
+ )
2236
+
2237
+ In Python, all classes are themselves instances of other classes. The class of
2238
+ a class is known as that class's :term: `metaclass `, and most classes have the
2239
+ :class: `type ` class as their metaclass. :class: `type ` does not define
2240
+ :meth: `~object.__getitem__ `, meaning that expressions such as ``list[int] ``,
2241
+ ``dict[str, float] `` and ``tuple[str, bytes] `` all result in
2242
+ :meth: `~object.__class_getitem__ ` being called::
2243
+
2244
+ >>> # list has class "type" as its metaclass, like most classes:
2245
+ >>> type(list)
2246
+ <class 'type'>
2247
+ >>> type(dict) == type(list) == type(tuple) == type(str) == type(bytes)
2248
+ True
2249
+ >>> # "list[int]" calls "list.__class_getitem__(int)"
2250
+ >>> list[int]
2251
+ list[int]
2252
+ >>> # list.__class_getitem__ returns a GenericAlias object:
2253
+ >>> type(list[int])
2254
+ <class 'types.GenericAlias'>
2255
+
2256
+ However, if a class has a custom metaclass that defines
2257
+ :meth: `~object.__getitem__ `, subscribing the class may result in different
2258
+ behaviour. An example of this can be found in the :mod: `enum ` module::
2259
+
2260
+ >>> from enum import Enum
2261
+ >>> class Menu(Enum):
2262
+ ... """A breakfast menu"""
2263
+ ... SPAM = 'spam'
2264
+ ... BACON = 'bacon'
2265
+ ...
2266
+ >>> # Enum classes have a custom metaclass:
2267
+ >>> type(Menu)
2268
+ <class 'enum.EnumMeta'>
2269
+ >>> # EnumMeta defines __getitem__,
2270
+ >>> # so __class_getitem__ is not called,
2271
+ >>> # and the result is not a GenericAlias object:
2272
+ >>> Menu['SPAM']
2273
+ <Menu.SPAM: 'spam'>
2274
+ >>> type(Menu['SPAM'])
2275
+ <enum 'Menu'>
2276
+
2277
+
2278
+ .. seealso ::
2279
+ :pep: `560 ` - Core Support for typing module and generic types
2280
+ Introducing :meth: `~object.__class_getitem__ `, and outlining when a
2281
+ :ref: `subscription<subscriptions> ` results in ``__class_getitem__() ``
2282
+ being called instead of :meth: `~object.__getitem__ `
2163
2283
2164
2284
2165
2285
.. _callable-types :
@@ -2259,19 +2379,27 @@ through the object's keys; for sequences, it should iterate through the values.
2259
2379
2260
2380
.. method :: object.__getitem__(self, key)
2261
2381
2262
- Called to implement evaluation of ``self[key] ``. For sequence types, the
2263
- accepted keys should be integers and slice objects. Note that the special
2264
- interpretation of negative indexes (if the class wishes to emulate a sequence
2265
- type) is up to the :meth: `__getitem__ ` method. If *key * is of an inappropriate
2266
- type, :exc: `TypeError ` may be raised; if of a value outside the set of indexes
2267
- for the sequence (after any special interpretation of negative values),
2268
- :exc: `IndexError ` should be raised. For mapping types, if *key * is missing (not
2269
- in the container), :exc: `KeyError ` should be raised.
2382
+ Called to implement evaluation of ``self[key] ``. For :term: `sequence ` types,
2383
+ the accepted keys should be integers and slice objects. Note that the
2384
+ special interpretation of negative indexes (if the class wishes to emulate a
2385
+ :term: `sequence ` type) is up to the :meth: `__getitem__ ` method. If *key * is
2386
+ of an inappropriate type, :exc: `TypeError ` may be raised; if of a value
2387
+ outside the set of indexes for the sequence (after any special
2388
+ interpretation of negative values), :exc: `IndexError ` should be raised. For
2389
+ :term: `mapping ` types, if *key * is missing (not in the container),
2390
+ :exc: `KeyError ` should be raised.
2391
+
2392
+ .. note ::
2393
+
2394
+ :keyword: `for ` loops expect that an :exc: `IndexError ` will be raised for
2395
+ illegal indexes to allow proper detection of the end of the sequence.
2270
2396
2271
2397
.. note ::
2272
2398
2273
- :keyword: `for ` loops expect that an :exc: `IndexError ` will be raised for illegal
2274
- indexes to allow proper detection of the end of the sequence.
2399
+ When :ref: `subscripting<subscriptions> ` a *class *, the special
2400
+ class method :meth: `~object.__class_getitem__ ` may be called instead of
2401
+ ``__getitem__() ``. See :ref: `classgetitem-versus-getitem ` for more
2402
+ details.
2275
2403
2276
2404
2277
2405
.. method :: object.__setitem__(self, key, value)
0 commit comments