@@ -2215,22 +2215,142 @@ case the instance is itself a class.
2215
2215
Emulating generic types
2216
2216
-----------------------
2217
2217
2218
- One can implement the generic class syntax as specified by :pep: `484 `
2219
- (for example ``List[int] ``) by defining a special method:
2218
+ When using :term: `type annotations<annotation> `, it is often useful to
2219
+ *parameterize * a :term: `generic type ` using Python's square-brackets notation.
2220
+ For example, the annotation ``list[int] `` might be used to signify a
2221
+ :class: `list ` in which all the elements are of type :class: `int `.
2222
+
2223
+ .. seealso ::
2224
+
2225
+ :pep: `484 ` - Type Hints
2226
+ Introducing Python's framework for type annotations
2227
+
2228
+ :ref: `Generic Alias Types<types-genericalias> `
2229
+ Documentation for objects representing parameterized generic classes
2230
+
2231
+ :ref: `Generics `, :ref: `user-defined generics<user-defined-generics> ` and :class: `typing.Generic `
2232
+ Documentation on how to implement generic classes that can be
2233
+ parameterized at runtime and understood by static type-checkers.
2234
+
2235
+ A class can *generally * only be parameterized if it defines the special
2236
+ class method ``__class_getitem__() ``.
2220
2237
2221
2238
.. classmethod :: object.__class_getitem__(cls, key)
2222
2239
2223
2240
Return an object representing the specialization of a generic class
2224
2241
by type arguments found in *key *.
2225
2242
2226
- This method is looked up on the class object itself, and when defined in
2227
- the class body, this method is implicitly a class method. Note, this
2228
- mechanism is primarily reserved for use with static type hints, other usage
2229
- is discouraged.
2243
+ When defined on a class, ``__class_getitem__() `` is automatically a class
2244
+ method. As such, there is no need for it to be decorated with
2245
+ :func: `@classmethod<classmethod> ` when it is defined.
2230
2246
2231
- .. seealso ::
2232
2247
2233
- :pep: `560 ` - Core support for typing module and generic types
2248
+ The purpose of *__class_getitem__ *
2249
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2250
+
2251
+ The purpose of :meth: `~object.__class_getitem__ ` is to allow runtime
2252
+ parameterization of standard-library generic classes in order to more easily
2253
+ apply :term: `type hints<type hint> ` to these classes.
2254
+
2255
+ To implement custom generic classes that can be parameterized at runtime and
2256
+ understood by static type-checkers, users should either inherit from a standard
2257
+ library class that already implements :meth: `~object.__class_getitem__ `, or
2258
+ inherit from :class: `typing.Generic `, which has its own implementation of
2259
+ ``__class_getitem__() ``.
2260
+
2261
+ Custom implementations of :meth: `~object.__class_getitem__ ` on classes defined
2262
+ outside of the standard library may not be understood by third-party
2263
+ type-checkers such as mypy. Using ``__class_getitem__() `` on any class for
2264
+ purposes other than type hinting is discouraged.
2265
+
2266
+
2267
+ .. _classgetitem-versus-getitem :
2268
+
2269
+
2270
+ *__class_getitem__ * versus *__getitem__ *
2271
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2272
+
2273
+ Usually, the :ref: `subscription<subscriptions> ` of an object using square
2274
+ brackets will call the :meth: `~object.__getitem__ ` instance method defined on
2275
+ the object's class. However, if the object being subscribed is itself a class,
2276
+ the class method :meth: `~object.__class_getitem__ ` may be called instead.
2277
+ ``__class_getitem__() `` should return a :ref: `GenericAlias<types-genericalias> `
2278
+ object if it is properly defined.
2279
+
2280
+ Presented with the :term: `expression ` ``obj[x] ``, the Python interpreter
2281
+ follows something like the following process to decide whether
2282
+ :meth: `~object.__getitem__ ` or :meth: `~object.__class_getitem__ ` should be
2283
+ called::
2284
+
2285
+ from inspect import isclass
2286
+
2287
+ def subscribe(obj, x):
2288
+ """Return the result of the expression `obj[x]`"""
2289
+
2290
+ class_of_obj = type(obj)
2291
+
2292
+ # If the class of obj defines __getitem__,
2293
+ # call class_of_obj.__getitem__(obj, x)
2294
+ if hasattr(class_of_obj, '__getitem__'):
2295
+ return class_of_obj.__getitem__(obj, x)
2296
+
2297
+ # Else, if obj is a class and defines __class_getitem__,
2298
+ # call obj.__class_getitem__(x)
2299
+ elif isclass(obj) and hasattr(obj, '__class_getitem__'):
2300
+ return obj.__class_getitem__(x)
2301
+
2302
+ # Else, raise an exception
2303
+ else:
2304
+ raise TypeError(
2305
+ f"'{class_of_obj.__name__}' object is not subscriptable"
2306
+ )
2307
+
2308
+ In Python, all classes are themselves instances of other classes. The class of
2309
+ a class is known as that class's :term: `metaclass `, and most classes have the
2310
+ :class: `type ` class as their metaclass. :class: `type ` does not define
2311
+ :meth: `~object.__getitem__ `, meaning that expressions such as ``list[int] ``,
2312
+ ``dict[str, float] `` and ``tuple[str, bytes] `` all result in
2313
+ :meth: `~object.__class_getitem__ ` being called::
2314
+
2315
+ >>> # list has class "type" as its metaclass, like most classes:
2316
+ >>> type(list)
2317
+ <class 'type'>
2318
+ >>> type(dict) == type(list) == type(tuple) == type(str) == type(bytes)
2319
+ True
2320
+ >>> # "list[int]" calls "list.__class_getitem__(int)"
2321
+ >>> list[int]
2322
+ list[int]
2323
+ >>> # list.__class_getitem__ returns a GenericAlias object:
2324
+ >>> type(list[int])
2325
+ <class 'types.GenericAlias'>
2326
+
2327
+ However, if a class has a custom metaclass that defines
2328
+ :meth: `~object.__getitem__ `, subscribing the class may result in different
2329
+ behaviour. An example of this can be found in the :mod: `enum ` module::
2330
+
2331
+ >>> from enum import Enum
2332
+ >>> class Menu(Enum):
2333
+ ... """A breakfast menu"""
2334
+ ... SPAM = 'spam'
2335
+ ... BACON = 'bacon'
2336
+ ...
2337
+ >>> # Enum classes have a custom metaclass:
2338
+ >>> type(Menu)
2339
+ <class 'enum.EnumMeta'>
2340
+ >>> # EnumMeta defines __getitem__,
2341
+ >>> # so __class_getitem__ is not called,
2342
+ >>> # and the result is not a GenericAlias object:
2343
+ >>> Menu['SPAM']
2344
+ <Menu.SPAM: 'spam'>
2345
+ >>> type(Menu['SPAM'])
2346
+ <enum 'Menu'>
2347
+
2348
+
2349
+ .. seealso ::
2350
+ :pep: `560 ` - Core Support for typing module and generic types
2351
+ Introducing :meth: `~object.__class_getitem__ `, and outlining when a
2352
+ :ref: `subscription<subscriptions> ` results in ``__class_getitem__() ``
2353
+ being called instead of :meth: `~object.__getitem__ `
2234
2354
2235
2355
2236
2356
.. _callable-types :
@@ -2330,19 +2450,27 @@ through the object's keys; for sequences, it should iterate through the values.
2330
2450
2331
2451
.. method :: object.__getitem__(self, key)
2332
2452
2333
- Called to implement evaluation of ``self[key] ``. For sequence types, the
2334
- accepted keys should be integers and slice objects. Note that the special
2335
- interpretation of negative indexes (if the class wishes to emulate a sequence
2336
- type) is up to the :meth: `__getitem__ ` method. If *key * is of an inappropriate
2337
- type, :exc: `TypeError ` may be raised; if of a value outside the set of indexes
2338
- for the sequence (after any special interpretation of negative values),
2339
- :exc: `IndexError ` should be raised. For mapping types, if *key * is missing (not
2340
- in the container), :exc: `KeyError ` should be raised.
2453
+ Called to implement evaluation of ``self[key] ``. For :term: `sequence ` types,
2454
+ the accepted keys should be integers and slice objects. Note that the
2455
+ special interpretation of negative indexes (if the class wishes to emulate a
2456
+ :term: `sequence ` type) is up to the :meth: `__getitem__ ` method. If *key * is
2457
+ of an inappropriate type, :exc: `TypeError ` may be raised; if of a value
2458
+ outside the set of indexes for the sequence (after any special
2459
+ interpretation of negative values), :exc: `IndexError ` should be raised. For
2460
+ :term: `mapping ` types, if *key * is missing (not in the container),
2461
+ :exc: `KeyError ` should be raised.
2462
+
2463
+ .. note ::
2464
+
2465
+ :keyword: `for ` loops expect that an :exc: `IndexError ` will be raised for
2466
+ illegal indexes to allow proper detection of the end of the sequence.
2341
2467
2342
2468
.. note ::
2343
2469
2344
- :keyword: `for ` loops expect that an :exc: `IndexError ` will be raised for illegal
2345
- indexes to allow proper detection of the end of the sequence.
2470
+ When :ref: `subscripting<subscriptions> ` a *class *, the special
2471
+ class method :meth: `~object.__class_getitem__ ` may be called instead of
2472
+ ``__getitem__() ``. See :ref: `classgetitem-versus-getitem ` for more
2473
+ details.
2346
2474
2347
2475
2348
2476
.. method :: object.__setitem__(self, key, value)
0 commit comments