@@ -2180,22 +2180,142 @@ case the instance is itself a class.
2180
2180
Emulating generic types
2181
2181
-----------------------
2182
2182
2183
- One can implement the generic class syntax as specified by :pep: `484 `
2184
- (for example ``List[int] ``) by defining a special method:
2183
+ When using :term: `type annotations<annotation> `, it is often useful to
2184
+ *parameterize * a :term: `generic type ` using Python's square-brackets notation.
2185
+ For example, the annotation ``list[int] `` might be used to signify a
2186
+ :class: `list ` in which all the elements are of type :class: `int `.
2187
+
2188
+ .. seealso ::
2189
+
2190
+ :pep: `484 ` - Type Hints
2191
+ Introducing Python's framework for type annotations
2192
+
2193
+ :ref: `Generic Alias Types<types-genericalias> `
2194
+ Documentation for objects representing parameterized generic classes
2195
+
2196
+ :ref: `Generics `, :ref: `user-defined generics<user-defined-generics> ` and :class: `typing.Generic `
2197
+ Documentation on how to implement generic classes that can be
2198
+ parameterized at runtime and understood by static type-checkers.
2199
+
2200
+ A class can *generally * only be parameterized if it defines the special
2201
+ class method ``__class_getitem__() ``.
2185
2202
2186
2203
.. classmethod :: object.__class_getitem__(cls, key)
2187
2204
2188
2205
Return an object representing the specialization of a generic class
2189
2206
by type arguments found in *key *.
2190
2207
2191
- This method is looked up on the class object itself, and when defined in
2192
- the class body, this method is implicitly a class method. Note, this
2193
- mechanism is primarily reserved for use with static type hints, other usage
2194
- is discouraged.
2208
+ When defined on a class, ``__class_getitem__() `` is automatically a class
2209
+ method. As such, there is no need for it to be decorated with
2210
+ :func: `@classmethod<classmethod> ` when it is defined.
2195
2211
2196
- .. seealso ::
2197
2212
2198
- :pep: `560 ` - Core support for typing module and generic types
2213
+ The purpose of *__class_getitem__ *
2214
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2215
+
2216
+ The purpose of :meth: `~object.__class_getitem__ ` is to allow runtime
2217
+ parameterization of standard-library generic classes in order to more easily
2218
+ apply :term: `type hints<type hint> ` to these classes.
2219
+
2220
+ To implement custom generic classes that can be parameterized at runtime and
2221
+ understood by static type-checkers, users should either inherit from a standard
2222
+ library class that already implements :meth: `~object.__class_getitem__ `, or
2223
+ inherit from :class: `typing.Generic `, which has its own implementation of
2224
+ ``__class_getitem__() ``.
2225
+
2226
+ Custom implementations of :meth: `~object.__class_getitem__ ` on classes defined
2227
+ outside of the standard library may not be understood by third-party
2228
+ type-checkers such as mypy. Using ``__class_getitem__() `` on any class for
2229
+ purposes other than type hinting is discouraged.
2230
+
2231
+
2232
+ .. _classgetitem-versus-getitem :
2233
+
2234
+
2235
+ *__class_getitem__ * versus *__getitem__ *
2236
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2237
+
2238
+ Usually, the :ref: `subscription<subscriptions> ` of an object using square
2239
+ brackets will call the :meth: `~object.__getitem__ ` instance method defined on
2240
+ the object's class. However, if the object being subscribed is itself a class,
2241
+ the class method :meth: `~object.__class_getitem__ ` may be called instead.
2242
+ ``__class_getitem__() `` should return a :ref: `GenericAlias<types-genericalias> `
2243
+ object if it is properly defined.
2244
+
2245
+ Presented with the :term: `expression ` ``obj[x] ``, the Python interpreter
2246
+ follows something like the following process to decide whether
2247
+ :meth: `~object.__getitem__ ` or :meth: `~object.__class_getitem__ ` should be
2248
+ called::
2249
+
2250
+ from inspect import isclass
2251
+
2252
+ def subscribe(obj, x):
2253
+ """Return the result of the expression `obj[x]`"""
2254
+
2255
+ class_of_obj = type(obj)
2256
+
2257
+ # If the class of obj defines __getitem__,
2258
+ # call class_of_obj.__getitem__(obj, x)
2259
+ if hasattr(class_of_obj, '__getitem__'):
2260
+ return class_of_obj.__getitem__(obj, x)
2261
+
2262
+ # Else, if obj is a class and defines __class_getitem__,
2263
+ # call obj.__class_getitem__(x)
2264
+ elif isclass(obj) and hasattr(obj, '__class_getitem__'):
2265
+ return obj.__class_getitem__(x)
2266
+
2267
+ # Else, raise an exception
2268
+ else:
2269
+ raise TypeError(
2270
+ f"'{class_of_obj.__name__}' object is not subscriptable"
2271
+ )
2272
+
2273
+ In Python, all classes are themselves instances of other classes. The class of
2274
+ a class is known as that class's :term: `metaclass `, and most classes have the
2275
+ :class: `type ` class as their metaclass. :class: `type ` does not define
2276
+ :meth: `~object.__getitem__ `, meaning that expressions such as ``list[int] ``,
2277
+ ``dict[str, float] `` and ``tuple[str, bytes] `` all result in
2278
+ :meth: `~object.__class_getitem__ ` being called::
2279
+
2280
+ >>> # list has class "type" as its metaclass, like most classes:
2281
+ >>> type(list)
2282
+ <class 'type'>
2283
+ >>> type(dict) == type(list) == type(tuple) == type(str) == type(bytes)
2284
+ True
2285
+ >>> # "list[int]" calls "list.__class_getitem__(int)"
2286
+ >>> list[int]
2287
+ list[int]
2288
+ >>> # list.__class_getitem__ returns a GenericAlias object:
2289
+ >>> type(list[int])
2290
+ <class 'types.GenericAlias'>
2291
+
2292
+ However, if a class has a custom metaclass that defines
2293
+ :meth: `~object.__getitem__ `, subscribing the class may result in different
2294
+ behaviour. An example of this can be found in the :mod: `enum ` module::
2295
+
2296
+ >>> from enum import Enum
2297
+ >>> class Menu(Enum):
2298
+ ... """A breakfast menu"""
2299
+ ... SPAM = 'spam'
2300
+ ... BACON = 'bacon'
2301
+ ...
2302
+ >>> # Enum classes have a custom metaclass:
2303
+ >>> type(Menu)
2304
+ <class 'enum.EnumMeta'>
2305
+ >>> # EnumMeta defines __getitem__,
2306
+ >>> # so __class_getitem__ is not called,
2307
+ >>> # and the result is not a GenericAlias object:
2308
+ >>> Menu['SPAM']
2309
+ <Menu.SPAM: 'spam'>
2310
+ >>> type(Menu['SPAM'])
2311
+ <enum 'Menu'>
2312
+
2313
+
2314
+ .. seealso ::
2315
+ :pep: `560 ` - Core Support for typing module and generic types
2316
+ Introducing :meth: `~object.__class_getitem__ `, and outlining when a
2317
+ :ref: `subscription<subscriptions> ` results in ``__class_getitem__() ``
2318
+ being called instead of :meth: `~object.__getitem__ `
2199
2319
2200
2320
2201
2321
.. _callable-types :
@@ -2295,19 +2415,27 @@ through the object's keys; for sequences, it should iterate through the values.
2295
2415
2296
2416
.. method :: object.__getitem__(self, key)
2297
2417
2298
- Called to implement evaluation of ``self[key] ``. For sequence types, the
2299
- accepted keys should be integers and slice objects. Note that the special
2300
- interpretation of negative indexes (if the class wishes to emulate a sequence
2301
- type) is up to the :meth: `__getitem__ ` method. If *key * is of an inappropriate
2302
- type, :exc: `TypeError ` may be raised; if of a value outside the set of indexes
2303
- for the sequence (after any special interpretation of negative values),
2304
- :exc: `IndexError ` should be raised. For mapping types, if *key * is missing (not
2305
- in the container), :exc: `KeyError ` should be raised.
2418
+ Called to implement evaluation of ``self[key] ``. For :term: `sequence ` types,
2419
+ the accepted keys should be integers and slice objects. Note that the
2420
+ special interpretation of negative indexes (if the class wishes to emulate a
2421
+ :term: `sequence ` type) is up to the :meth: `__getitem__ ` method. If *key * is
2422
+ of an inappropriate type, :exc: `TypeError ` may be raised; if of a value
2423
+ outside the set of indexes for the sequence (after any special
2424
+ interpretation of negative values), :exc: `IndexError ` should be raised. For
2425
+ :term: `mapping ` types, if *key * is missing (not in the container),
2426
+ :exc: `KeyError ` should be raised.
2427
+
2428
+ .. note ::
2429
+
2430
+ :keyword: `for ` loops expect that an :exc: `IndexError ` will be raised for
2431
+ illegal indexes to allow proper detection of the end of the sequence.
2306
2432
2307
2433
.. note ::
2308
2434
2309
- :keyword: `for ` loops expect that an :exc: `IndexError ` will be raised for illegal
2310
- indexes to allow proper detection of the end of the sequence.
2435
+ When :ref: `subscripting<subscriptions> ` a *class *, the special
2436
+ class method :meth: `~object.__class_getitem__ ` may be called instead of
2437
+ ``__getitem__() ``. See :ref: `classgetitem-versus-getitem ` for more
2438
+ details.
2311
2439
2312
2440
2313
2441
.. method :: object.__setitem__(self, key, value)
0 commit comments