@@ -151,15 +151,16 @@ In order to support the above use cases, we introduce
151
151
but for a *tuple * of types.
152
152
153
153
In addition, we introduce a new use for the star operator: to 'unpack'
154
- ``TypeVarTuple `` instances and tuple types. Unpacking a
155
- `` TypeVarTuple `` or tuple type is the typing equivalent of unpacking a
156
- variable or a tuple of values.
154
+ ``TypeVarTuple `` instances and tuple types such as `` Tuple[int,
155
+ str] ``. Unpacking a `` TypeVarTuple `` or tuple type is the typing
156
+ equivalent of unpacking a variable or a tuple of values.
157
157
158
158
Type Variable Tuples
159
159
--------------------
160
160
161
- In the same way that a normal type variable is a stand-in for a single type,
162
- a type variable *tuple * is a stand-in for a *tuple * type.
161
+ In the same way that a normal type variable is a stand-in for a single
162
+ type such as ``int ``, a type variable *tuple * is a stand-in for a *tuple * type such as
163
+ ``Tuple[int, str] ``.
163
164
164
165
Type variable tuples are created with:
165
166
@@ -315,13 +316,6 @@ As of this PEP, only a single type variable tuple may appear in a type parameter
315
316
316
317
class Array(Generic[*Ts1, *Ts2]): ... # Error
317
318
318
- Only one unpacking may appear in a tuple:
319
-
320
- ::
321
-
322
- x: Tuple[int, *Ts, str, *Ts2] # Error
323
- y: Tuple[int, *Tuple[int, ...], str, *Tuple[str, ...]] # Error
324
-
325
319
Type Concatenation
326
320
------------------
327
321
@@ -364,68 +358,33 @@ Normal ``TypeVar`` instances can also be prefixed and/or suffixed:
364
358
Unpacking a Tuple Type
365
359
----------------------
366
360
367
- We mentioned that a ``TypeVarTuple `` simply stands for a tuple of
368
- types. Thus, we can cleanly replace any use of a ``TypeVarTuple `` in a
369
- function signature with a tuple type.
361
+ We mentioned that a ``TypeVarTuple `` stands for a tuple of types.
362
+ Since we can unpack an ``TypeVarTuple ``, for consistency, we also
363
+ allow unpacking a tuple type. As we shall see, this also enables a
364
+ number of interesting features.
365
+
370
366
371
367
Unpacking a Concrete Tuple Type
372
368
'''''''''''''''''''''''''''''''
373
369
374
370
Unpacking a concrete tuple type is analogous to unpacking a tuple of
375
371
values at runtime. ``Tuple[int, *Tuple[bool, bool], str] `` is
376
- equivalent to ``Tuple[int, bool, bool, str] ``. While this is unlikely
377
- to be useful by itself, we mention it to cleanly specify how we unpack
378
- a ``TypeVarTuple `` that is substituted by a concrete tuple type:
379
-
380
- ::
381
-
382
- def strip_and_add_float(x: Tuple[int, *Ts, str]) -> Tuple[float, *Ts, float]: ...
383
-
384
- When ``strip_and_add_float `` is called with a value that has a concrete
385
- tuple type, say, ``Tuple[int, bool, bool, str] ``, ``Ts `` is bound to
386
- the concrete tuple ``Tuple[bool, bool] ``.
387
-
388
- ::
389
-
390
- x: Tuple[int, bool, bool, str] = (1, True, False, "hello")
391
-
392
- y = strip_and_add_float(x)
393
- # Inferred type of y: Tuple[float, bool, bool, float]
394
-
395
- The inferred type is ``Tuple[float, bool, bool, float] `` because
396
- unpacking ``Tuple[bool, bool] `` in the return type ``Tuple[float, *Ts,
397
- float] `` gives back ``Tuple[float, bool, bool, float] ``.
372
+ equivalent to ``Tuple[int, bool, bool, str] ``.
398
373
399
374
Unpacking an Unbounded Tuple Type
400
375
'''''''''''''''''''''''''''''''''
401
376
402
377
Unpacking an unbounded tuple preserves the unbounded tuple as it is.
403
- ``Tuple[int, *Tuple[str, ...], str] `` signifies a tuple
404
- type where the first element is guaranteed to be of type ``int ``, the
405
- last element is guaranteed to be of type ``str ``, and there may be
406
- zero or more elements of type ``str `` in between. Note that
407
- ``Tuple[*Tuple[int, ...]] `` is equivalent to ``Tuple[int, ...] ``.
408
-
409
- Consider the following functions:
410
-
411
- ::
412
-
413
- def add_first_last(x: Tuple[*Ts]) -> Tuple[int, *Ts, str]: ...
414
-
415
- When ``add_first_last `` is called with a value that has an *unbounded *
416
- tuple type, say, ``Tuple[str, ...] ``, ``Ts `` is bound to the concrete
417
- tuple ``Tuple[str, ...] `` and substituted in the return type.
418
-
419
- ::
420
-
421
- x: Tuple[str, ...]
422
-
423
- y = add_first_last(x)
424
- # Inferred type of y: Tuple[int, *Tuple[str, ...], str]
425
-
426
-
427
- Unpacking unbounded tuples is useful in function signatures where we
428
- don't care about the exact elements and do not want to define an
378
+ That is, ``*Tuple[int, ...] `` remains ``*Tuple[int, ...] ``; there's no
379
+ simpler form. This enables us to specify types such as ``Tuple[int,
380
+ *Tuple[str, ...], str] `` - a tuple type where the first element is
381
+ guaranteed to be of type ``int ``, the last element is guaranteed to be
382
+ of type ``str ``, and the elements in the middle are zero or more
383
+ elements of type ``str ``. Note that ``Tuple[*Tuple[int, ...]] `` is
384
+ equivalent to ``Tuple[int, ...] ``.
385
+
386
+ Unpacking unbounded tuples is also useful in function signatures where
387
+ we don't care about the exact elements and don't want to define an
429
388
unnecessary ``TypeVarTuple ``:
430
389
431
390
::
@@ -444,25 +403,26 @@ unnecessary ``TypeVarTuple``:
444
403
process_batch_channels(z) # Error: Expected Channels.
445
404
446
405
447
- We can also pass a ``Tuple[int, ...] `` wherever a ``Tuple[ *Ts] `` is
406
+ We can also pass a ``* Tuple[int, ...] `` wherever a ``*Ts `` is
448
407
expected. This is useful when we have particularly dynamic code and
449
- cannot infer the precise number of dimensions or the precise types for
408
+ cannot state the precise number of dimensions or the precise types for
450
409
each of the dimensions. In those cases, we can smoothly fall back to
451
410
an unbounded tuple:
452
411
453
412
::
454
413
414
+ y: Array[*Tuple[Any, ...]] = read_from_file()
415
+
455
416
def expect_variadic_array(
456
417
x: Array[Batch, *Shape]
457
418
) -> None: ...
458
419
420
+ expect_variadic_array(y) # OK
421
+
459
422
def expect_precise_array(
460
423
x: Array[Batch, Height, Width, Channels]
461
424
) -> None: ...
462
425
463
- y: Array[*Tuple[Any, ...]] = read_from_file()
464
-
465
- expect_variadic_array(y) # OK
466
426
expect_precise_array(y) # OK
467
427
468
428
``Array[*Tuple[Any, ...]] `` stands for an array with an arbitrary
@@ -473,10 +433,21 @@ is bound to ``Tuple[Any, ...]``. In the call to
473
433
``Width ``, and ``Channels `` are all bound to ``Any ``.
474
434
475
435
This allows users to handle dynamic code gracefully while still
476
- explicitly marking the code as unsafe (by using ``*Tuple[Any, ...] ``).
477
- Otherwise, users would face noisy errors from the type checker every
478
- time they tried to use the variable ``y ``, which would hinder them
479
- when migrating a legacy code base to use ``TypeVarTuple ``.
436
+ explicitly marking the code as unsafe (by using ``y: Array[*Tuple[Any,
437
+ ...]] ``). Otherwise, users would face noisy errors from the type
438
+ checker every time they tried to use the variable ``y ``, which would
439
+ hinder them when migrating a legacy code base to use ``TypeVarTuple ``.
440
+
441
+ Multiple Unpackings in a Tuple: Not Allowed
442
+ ''''''''''''''''''''''''''''''''''''''''''
443
+
444
+ As with ``TypeVarTuple ``, only one unpacking may appear in a tuple:
445
+
446
+ ::
447
+
448
+ x: Tuple[int, *Ts, str, *Ts2] # Error
449
+ y: Tuple[int, *Tuple[int, ...], str, *Tuple[str, ...]] # Error
450
+
480
451
481
452
``*args `` as a Type Variable Tuple
482
453
----------------------------------
@@ -508,18 +479,19 @@ or suffixes of the variadic argument list. For example:
508
479
::
509
480
510
481
# os.execle takes arguments 'path, arg0, arg1, ..., env'
511
- def execle(path: str, *args: *Tuple[*Ts, Mapping[str, str] ]) -> None: ...
482
+ def execle(path: str, *args: *Tuple[*Ts, Env ]) -> None: ...
512
483
513
484
Note this this is different to
514
485
515
486
::
516
487
517
- def execle(path: str, *args: *Ts, env: Mapping[str, str] ) -> None: ...
488
+ def execle(path: str, *args: *Ts, env: Env ) -> None: ...
518
489
519
490
as this would make ``env `` a keyword-only argument.
520
491
521
- Unpacking an unbounded tuple is equivalent to the PEP 484 behavior of
522
- ``*args: int ``, which accepts zero or more values of type ``int ``:
492
+ Using an unpacked unbounded tuple is equivalent to the PEP 484
493
+ behavior [#pep-484-args ]_ of ``*args: int ``, which accepts zero or
494
+ more values of type ``int ``:
523
495
524
496
::
525
497
@@ -587,10 +559,10 @@ Type variable tuples can also be used in the arguments section of a
587
559
def __init__(
588
560
self,
589
561
target: Callable[[*Ts], None],
590
- args: Tuple[*Ts]
591
- ): ...
562
+ args: Tuple[*Ts],
563
+ ) -> None : ...
592
564
593
- def func(arg1: int, arg2: str): ...
565
+ def func(arg1: int, arg2: str) -> None : ...
594
566
595
567
Process(target=func, args=(0, 'foo')) # Valid
596
568
Process(target=func, args=('foo', 0)) # Error
@@ -621,7 +593,7 @@ the function:
621
593
def foo(*args: *Tuple[int, *Ts, T]) -> Tuple[T, *Ts]: ...
622
594
623
595
Behaviour when Type Parameters are not Specified
624
- ''''''''''''''''''''''''''''''''''''''''''''''''
596
+ ------------------------------------------------
625
597
626
598
When a generic class parameterised by a type variable tuple is used without
627
599
any type parameters, it behaves as if the type variable tuple was
@@ -729,7 +701,7 @@ Normal ``TypeVar`` instances can also be used in such aliases:
729
701
Foo[str, int]
730
702
# T bound to float, Ts to Tuple[()]
731
703
Foo[float]
732
- # T bound to Any, Ts to an arbitrary number of Any
704
+ # T bound to Any, Ts to an Tuple[ Any, ...]
733
705
Foo
734
706
735
707
Overloads for Accessing Individual Types
@@ -1470,6 +1442,8 @@ References
1470
1442
1471
1443
.. [#dan-endorsement ] https://mail.python.org/archives/list/python-dev@python.org/message/HTCARTYYCHETAMHB6OVRNR5EW5T2CP4J/
1472
1444
1445
+ .. [#pep-484-args ] https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values
1446
+
1473
1447
Copyright
1474
1448
=========
1475
1449
0 commit comments