1
1
PEP: 560
2
- Title: Core support for generic types
2
+ Title: Core support for typing module and generic types
3
3
Author: Ivan Levkivskyi <
[email protected] >
4
4
Status: Draft
5
5
Type: Standards Track
@@ -18,7 +18,7 @@ the ``typing`` module are extensively used by the community, e.g. PEP 526
18
18
and PEP 557 extend the usage of type hints, and the backport of ``typing ``
19
19
on PyPI has 1M downloads/month. Therefore, this restriction can be removed.
20
20
It is proposed to add two special methods ``__class_getitem__ `` and
21
- ``__subclass_base__ `` to the core CPython for better support of
21
+ ``__mro_entry__ `` to the core CPython for better support of
22
22
generic types.
23
23
24
24
@@ -134,31 +134,72 @@ For example::
134
134
Note that this method is used as a fallback, so if a metaclass defines
135
135
``__getitem__ ``, then that will have the priority.
136
136
137
- ``__subclass_base__ ``
138
- ---------------------
137
+
138
+ ``__mro_entry__ ``
139
+ -----------------
139
140
140
141
If an object that is not a class object appears in the bases of a class
141
- definition, then ``__subclass_base__ `` is searched on it. If found,
142
+ definition, then ``__mro_entry__ `` is searched on it. If found,
142
143
it is called with the original tuple of bases as an argument. If the result
143
144
of the call is not ``None ``, then it is substituted instead of this object.
144
145
Otherwise (if the result is ``None ``), the base is just removed. This is
145
146
necessary to avoid inconsistent MRO errors, that are currently prevented by
146
147
manipulations in ``GenericMeta.__new__ ``. After creating the class,
147
148
the original bases are saved in ``__orig_bases__ `` (currently this is also
148
- done by the metaclass).
149
+ done by the metaclass). For example::
150
+
151
+ class GenericAlias:
152
+ def __init__(self, origin, item):
153
+ self.origin = origin
154
+ self.item = item
155
+ def __mro_entry__(self, bases):
156
+ return self.origin
157
+
158
+ class NewList:
159
+ def __class_getitem__(cls, item):
160
+ return GenericAlias(cls, item)
161
+
162
+ class Tokens(NewList[int]):
163
+ ...
164
+
165
+ assert Tokens.__bases__ == (NewList,)
166
+ assert Tokens.__orig_bases__ == (NewList[int],)
167
+ assert Tokens.__mro__ == (Tokens, NewList, object)
168
+
169
+ NOTE: These two method names are reserved for use by the ``typing `` module
170
+ and the generic types machinery, and any other use is discouraged.
171
+ The reference implementation (with tests) can be found in [4 ]_, and
172
+ the proposal was originally posted and discussed on the ``typing `` tracker,
173
+ see [5 ]_.
174
+
175
+
176
+ Dynamic class creation and ``types.resolve_bases ``
177
+ --------------------------------------------------
178
+
179
+ ``type.__new__ `` will not perform any MRO entry resolution. So that a direct
180
+ call ``type('Tokens', (List[int],), {}) `` will fail. This is done for
181
+ performance reasons and to minimize the number of implicit transformations.
182
+ Instead, a helper function ``resolve_bases `` will be added to
183
+ the ``types `` module to allow an explicit ``__mro_entry__ `` resolution in
184
+ the context of dynamic class creation. Correspondingly, ``types.new_class ``
185
+ will be updated to reflect the new class creation steps while maintaining
186
+ the backwards compatibility::
149
187
150
- NOTE: These two method names are reserved for exclusive use by
151
- the ``typing `` module and the generic types machinery, and any other use is
152
- strongly discouraged. The reference implementation (with tests) can be found
153
- in [4 ]_, and the proposal was originally posted and discussed on
154
- the ``typing `` tracker, see [5 ]_.
188
+ def new_class(name, bases=(), kwds=None, exec_body=None):
189
+ resolved_bases = resolve_bases(bases) # This step is added
190
+ meta, ns, kwds = prepare_class(name, resolved_bases, kwds)
191
+ if exec_body is not None:
192
+ exec_body(ns)
193
+ cls = meta(name, resolved_bases, ns, **kwds)
194
+ cls.__orig_bases__ = bases # This step is added
195
+ return cls
155
196
156
197
157
198
Backwards compatibility and impact on users who don't use ``typing ``
158
199
====================================================================
159
200
160
201
This proposal may break code that currently uses the names
161
- ``__class_getitem__ `` and ``__subclass_base__ ``. (But the language
202
+ ``__class_getitem__ `` and ``__mro_entry__ ``. (But the language
162
203
reference explicitly reserves *all * undocumented dunder names, and
163
204
allows "breakage without warning"; see [6 ]_.)
164
205
0 commit comments