PEP 560: Wording improvements after discussion on python-dev (#473)

This commit is contained in:
Ivan Levkivskyi 2017-11-17 23:16:43 +01:00 committed by Guido van Rossum
parent 51a8f2f495
commit 17564eff05
1 changed files with 24 additions and 20 deletions

View File

@ -37,19 +37,18 @@ 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 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
because subscripted generic types (see PEP 484 for definition of terms used
in this PEP) are class objects (see also [1]_). There are three main ways how
the performance can be improved with the help of the proposed special methods:
- Creation of generic classes is slow since the ``GenericMeta.__new__`` is
very slow; we will not need it anymore.
- Very long MROs for generic classes will be twice shorter; they are present
because we duplicate the ``collections.abc`` inheritance chain
in ``typing``.
- Very long method resolution orders (MROs) for generic classes will be
half as long; they are present because we duplicate the ``collections.abc``
inheritance chain in ``typing``.
- Time of instantiation of generic classes will be improved
(this is minor however).
- Instantiation of generic classes will be faster (this is minor however).
Metaclass conflicts
@ -138,16 +137,22 @@ Note that this method is used as a fallback, so if a metaclass defines
``__mro_entries__``
-------------------
If an object that is not a class object appears in the bases of a class
definition, then ``__mro_entries__`` is searched on it. If found,
it is called with the original tuple of bases as an argument. The result
of the call must be a tuple, that is unpacked in the bases classes in place
of this object. (If the tuple is empty, this means that the original bases is
simply discarded.) Using the method API instead of just an attribute is
necessary to avoid inconsistent MRO errors, and perform other manipulations
that are currently done by ``GenericMeta.__new__``. After creating the class,
the original bases are saved in ``__orig_bases__`` (currently this is also
done by the metaclass). For example::
If an object that is not a class object appears in the tuple of bases of
a class definition, then method ``__mro_entries__`` is searched on it.
If found, it is called with the original tuple of bases as an argument.
The result of the call must be a tuple, that is unpacked in the base classes
in place of this object. (If the tuple is empty, this means that the original
bases is simply discarded.) If there are more than one object with
``__mro_entries__``, then all of them are called with the same original tuple
of bases. This step happens first in the process of creation of a class,
all other steps, including checks for duplicate bases and MRO calculation,
happen normally with the updated bases.
Using the method API instead of just an attribute is necessary to avoid
inconsistent MRO errors, and perform other manipulations that are currently
done by ``GenericMeta.__new__``. The original bases are stored as
``__orig_bases__`` in the class namespace (currently this is also done by
the metaclass). For example::
class GenericAlias:
def __init__(self, origin, item):
@ -191,9 +196,8 @@ the backwards compatibility::
meta, ns, kwds = prepare_class(name, resolved_bases, kwds)
if exec_body is not None:
exec_body(ns)
cls = meta(name, resolved_bases, ns, **kwds)
cls.__orig_bases__ = bases # This step is added
return cls
ns['__orig_bases__'] = bases # This step is added
return meta(name, resolved_bases, ns, **kwds)
Backwards compatibility and impact on users who don't use ``typing``