diff --git a/pep-0560.rst b/pep-0560.rst index ec44f71d1..a27f0a6a5 100644 --- a/pep-0560.rst +++ b/pep-0560.rst @@ -25,19 +25,19 @@ generic types. Rationale ========= -The restriction to not modify the core CPython interpreter lead to some +The restriction to not modify the core CPython interpreter led to some design decisions that became questionable when the ``typing`` module started -to be widely used. There are three main points of concerns: +to be widely used. There are three main points of concern: performance of the ``typing`` module, metaclass conflicts, and the large number of hacks currently used in ``typing``. -Performance: ------------- +Performance +----------- The ``typing`` module is one of the heaviest and slowest modules in the standard library even with all the optimizations made. Mainly this is -because subscripted generic types (see PEP 484 for definition of terms +because of subscripted generic types (see PEP 484 for definition of terms used in this PEP) are class objects (see also [1]_). The three main ways how the performance can be improved with the help of the proposed special methods: @@ -52,8 +52,8 @@ the performance can be improved with the help of the proposed special methods: (this is minor however). -Metaclass conflicts: --------------------- +Metaclass conflicts +------------------- All generic types are instances of ``GenericMeta``, so if a user uses a custom metaclass, then it is hard to make a corresponding class generic. @@ -70,17 +70,17 @@ but this is not always practical or even possible. With the help of the proposed special attributes the ``GenericMeta`` metaclass will not be needed. -Hacks and bugs that will be removed by this proposal: ------------------------------------------------------ +Hacks and bugs that will be removed by this proposal +---------------------------------------------------- -- ``_generic_new`` hack that exists since ``__init__`` is not called on +- ``_generic_new`` hack that exists because ``__init__`` is not called on instances with a type differing form the type whose ``__new__`` was called, ``C[int]().__class__ is C``. - ``_next_in_mro`` speed hack will be not necessary since subscription will not create new classes. -- Ugly ``sys._getframe`` hack, this one is particularly nasty, since it looks +- Ugly ``sys._getframe`` hack. This one is particularly nasty since it looks like we can't remove it without changes outside ``typing``. - Currently generics do dangerous things with private ABC caches @@ -89,14 +89,14 @@ Hacks and bugs that will be removed by this proposal: re-implement ``ABCMeta`` in C. - Problems with sharing attributes between subscripted generics, - see [3]_. Current solution already uses ``__getattr__`` and ``__setattr__``, + see [3]_. The current solution already uses ``__getattr__`` and ``__setattr__``, but it is still incomplete, and solving this without the current proposal will be hard and will need ``__getattribute__``. -- ``_no_slots_copy`` hack, where we clean-up the class dictionary on every +- ``_no_slots_copy`` hack, where we clean up the class dictionary on every subscription thus allowing generics with ``__slots__``. -- General complexity of the ``typing`` module, the new proposal will not +- General complexity of the ``typing`` module. The new proposal will not only allow to remove the above mentioned hacks/bugs, but also simplify the implementation, so that it will be easier to maintain. @@ -104,9 +104,12 @@ Hacks and bugs that will be removed by this proposal: Specification ============= +``__class_getitem__`` +--------------------- + The idea of ``__class_getitem__`` is simple: it is an exact analog of ``__getitem__`` with an exception that it is called on a class that -defines it, not on its instances, this allows us to avoid +defines it, not on its instances. This allows us to avoid ``GenericMeta.__getitem__`` for things like ``Iterable[int]``. The ``__class_getitem__`` is automatically a class method and does not require ``@classmethod`` decorator (similar to @@ -131,8 +134,11 @@ For example:: Note that this method is used as a fallback, so if a metaclass defines ``__getitem__``, then that will have the priority. +``__subclass_base__`` +--------------------- + If an object that is not a class object appears in the bases of a class -definition, the ``__subclass_base__`` is searched on it. If found, +definition, then ``__subclass_base__`` is searched on it. If found, it is called with the original tuple of bases as an argument. If the result of the call is not ``None``, then it is substituted instead of this object. Otherwise (if the result is ``None``), the base is just removed. This is @@ -144,20 +150,22 @@ done by the metaclass). NOTE: These two method names are reserved for exclusive use by the ``typing`` module and the generic types machinery, and any other use is strongly discouraged. The reference implementation (with tests) can be found -in [4]_, the proposal was originally posted and discussed on +in [4]_, and the proposal was originally posted and discussed on the ``typing`` tracker, see [5]_. -Backwards compatibility and impact on users who don't use ``typing``: -===================================================================== +Backwards compatibility and impact on users who don't use ``typing`` +==================================================================== This proposal may break code that currently uses the names -``__class_getitem__`` and ``__subclass_base__``. +``__class_getitem__`` and ``__subclass_base__``. (But the language +reference explicitly reserves *all* undocumented dunder names, and +allows "breakage without warning"; see [6]_.) This proposal will support almost complete backwards compatibility with the current public generic types API; moreover the ``typing`` module is still provisional. The only two exceptions are that currently -``issubclass(List[int], List)`` returns True, with this proposal it will raise +``issubclass(List[int], List)`` returns True, while with this proposal it will raise ``TypeError``. Also ``issubclass(collections.abc.Iterable, typing.Iterable)`` will return ``False``, which is probably desirable, since currently we have a (virtual) inheritance cycle between these two classes. @@ -172,7 +180,7 @@ References .. [1] Discussion following Mark Shannon's presentation at Language Summit (https://github.com/python/typing/issues/432) -.. [2] Pull Request to implement shared generic ABC caches +.. [2] Pull Request to implement shared generic ABC caches (merged) (https://github.com/python/typing/pull/383) .. [3] An old bug with setting/accessing attributes on generic types @@ -184,6 +192,8 @@ References .. [5] Original proposal (https://github.com/python/typing/issues/468) +.. [6] Reserved classes of identifiers + (https://docs.python.org/3/reference/lexical_analysis.html#reserved-classes-of-identifiers) Copyright =========