@@ -17,8 +17,8 @@ Abstract
17
17
:pep: `589 ` defines a :ref: `class-based <typing:typeddict-class-based-syntax >`
18
18
and a :ref: `functional syntax <typing:typeddict-functional-syntax >` to create
19
19
typed dictionaries. In both scenarios, it requires defining a class or
20
- assigning to a value. In some situations, this can add unnecessary boilerplate,
21
- especially if the typed dictionary is only used once.
20
+ assigning to a value. In some situations, this can add unnecessary
21
+ boilerplate, especially if the typed dictionary is only used once.
22
22
23
23
This PEP proposes the addition of a new inlined syntax, by subscripting the
24
24
:class: `~typing.TypedDict ` type::
@@ -93,11 +93,15 @@ The :class:`~typing.TypedDict` class is made subscriptable, and accepts a
93
93
single type argument which must be a :class: `dict `, following the same
94
94
semantics as the :ref: `functional syntax <typing:typeddict-functional-syntax >`
95
95
(the dictionary keys are strings representing the field names, and values are
96
- valid :ref: `annotation expressions <typing:annotation-expression >`).
96
+ valid :ref: `annotation expressions <typing:annotation-expression >`). Only the
97
+ comma-separated list of ``key: value `` pairs within braces constructor
98
+ (``{k: <type>} ``) is allowed, and should be specified directly as the type
99
+ argument (i.e. it is not allowed to use a variable which was previously
100
+ assigned a :class: `dict ` instance).
97
101
98
102
Inlined typed dictionaries can be referred to as *anonymous *, meaning they
99
- don't have a name. For this reason, their :attr: ` ~type.__name__ ` attribute
100
- will be set to an empty string .
103
+ don't have a name (see the ` runtime behavior < Runtime behavior >`_
104
+ section) .
101
105
102
106
It is possible to define a nested inlined dictionary::
103
107
@@ -135,8 +139,6 @@ are bound to some outer scope::
135
139
136
140
InlinedTD = TypedDict[{'name': T}] # Not OK, `T` refers to a type variable that is not bound to any scope.
137
141
138
- **TODO ** closed
139
-
140
142
Typing specification changes
141
143
----------------------------
142
144
@@ -158,19 +160,20 @@ implemented as a function at runtime. To be made subscriptable, it will be
158
160
changed to be a class.
159
161
160
162
Creating an inlined typed dictionary results in a new class, so ``T1 `` and
161
- ``T2 `` are the same type (apart from the different :attr: ` ~type.__name__ `) ::
163
+ ``T2 `` are of the same type::
162
164
163
165
from typing import TypedDict
164
166
165
167
T1 = TypedDict('T1', {'a': int})
166
168
T2 = TypedDict[{'a': int}]
167
169
170
+ As inlined typed dictionaries are are meant to be *anonymous *, their
171
+ :attr: `~type.__name__ ` attribute will be set to an empty string.
168
172
169
173
Backwards Compatibility
170
174
=======================
171
175
172
- Apart from the :class: `~typing.TypedDict ` internal implementation change, this
173
- PEP does not bring any backwards incompatible changes.
176
+ This PEP does not bring any backwards incompatible changes.
174
177
175
178
176
179
Security Implications
@@ -236,7 +239,7 @@ While this would avoid having to import :class:`~typing.TypedDict` from
236
239
* For type checkers, :class: `dict ` is a regular class with two type variables.
237
240
Allowing :class: `dict ` to be parametrized with a single type argument would
238
241
require special casing from type checkers, as there is no way to express
239
- parametrization overloads. On ther other hand, :class: `~typing.TypedDict ` is
242
+ parametrization overloads. On the other hand, :class: `~typing.TypedDict ` is
240
243
already a :term: `special form <typing:special form> `.
241
244
242
245
* If future work extends what inlined typed dictionaries can do, we don't have
@@ -277,6 +280,13 @@ Should we allow the following?::
277
280
class SubTD(InlinedTD):
278
281
pass
279
282
283
+ What about defining an inlined typed dictionay extending another typed
284
+ dictionary?::
285
+
286
+ InlinedBase = TypedDict[{'a': int}]
287
+
288
+ Inlined = TypedDict[InlinedBase, {'b': int}]
289
+
280
290
Using ``typing.Dict `` with a single argument
281
291
--------------------------------------------
282
292
@@ -285,16 +295,39 @@ While using :class:`dict` isn't ideal, we could make use of
285
295
286
296
def get_movie() -> Dict[{'title': str}]: ...
287
297
288
- It is less verbose, doesn't have the baggage of :class: `dict `,
289
- and is defined as some kind of special form (an alias to the built-in
290
- ``dict ``).
298
+ It is less verbose, doesn't have the baggage of :class: `dict `, and is
299
+ already defined as some kind of special form.
291
300
292
301
However, it is currently marked as deprecated (although not scheduled for
293
302
removal), so it might be confusing to undeprecate it.
294
303
295
304
This would also set a precedent on typing constructs being parametrizable
296
305
with a different number of type arguments.
297
306
307
+ Should inlined typed dictionaries be proper classes?
308
+ ----------------------------------------------------
309
+
310
+ The PEP currently defines inlined typed dictionaries as type objects, to be in
311
+ line with the existing syntaxes. To work around the fact that they don't have
312
+ a name, their :attr: `~type.__name__ ` attribute is set to an empty string.
313
+
314
+ This is somewhat arbitrary, and an alternative name could be used as well
315
+ (e.g. ``'<TypedDict>' ``).
316
+
317
+ Alternatively, inlined typed dictionaries could be defined as instances of a
318
+ new (internal) typing class, e.g. :class: `!typing._InlinedTypedDict `. While
319
+ this solves the naming issue, it requires extra logic in the runtime
320
+ implementation to provide the introspection attributes (such as
321
+ :attr: `~typing.TypedDict.__total__ `), and tools relying on runtime
322
+ introspection would have to add proper support for this new type.
323
+
324
+ Inlined typed dictionaries and extra items
325
+ ------------------------------------------
326
+
327
+ :pep: `728 ` introduces the concept of *closed * type dictionaries. Inlined
328
+ typed dictionaries should probably be implicitly *closed *, but it may be
329
+ better to wait for :pep: `728 ` to be accepted first.
330
+
298
331
299
332
Copyright
300
333
=========
0 commit comments