Skip to content

Commit 2548e68

Browse files
committed
PEP 646: fix nits and typos.
1 parent 383a441 commit 2548e68

File tree

1 file changed

+74
-93
lines changed

1 file changed

+74
-93
lines changed

pep-0646.rst

Lines changed: 74 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -151,15 +151,16 @@ In order to support the above use cases, we introduce
151151
but for a *tuple* of types.
152152

153153
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.
157157

158158
Type Variable Tuples
159159
--------------------
160160

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]``.
163164

164165
Type variable tuples are created with:
165166

@@ -169,8 +170,8 @@ Type variable tuples are created with:
169170

170171
Ts = TypeVarTuple('Ts')
171172

172-
Using a Type Variable Tuple in Generic Classes
173-
''''''''''''''''''''''''''''''''''''''''''''''
173+
Using Type Variable Tuples in Generic Classes
174+
'''''''''''''''''''''''''''''''''''''''''''''
174175

175176
Type variable tuples behave like a number of individual type variables packed in a
176177
``Tuple``. To understand this, consider the following example:
@@ -204,8 +205,8 @@ and so on:
204205
y: Array[Batch, Height, Width] = Array()
205206
z: Array[Time, Batch, Height, Width] = Array()
206207

207-
Using a Type Variable Tuple in Functions
208-
''''''''''''''''''''''''''''''''''''''''
208+
Using Type Variable Tuples in Functions
209+
'''''''''''''''''''''''''''''''''''''''
209210

210211
Type variable tuples can be used anywhere a normal ``TypeVar`` can.
211212
This includes class definitions, as shown above, as well as function
@@ -315,12 +316,10 @@ As of this PEP, only a single type variable tuple may appear in a type parameter
315316

316317
class Array(Generic[*Ts1, *Ts2]): ... # Error
317318

318-
Only one unpacking may appear in a tuple:
319+
The reason is that multiple type variable tuples make it ambiguous
320+
which parameters get bound to which type variable tuple: ::
319321

320-
::
321-
322-
x: Tuple[int, *Ts, str, *Ts2] # Error
323-
y: Tuple[int, *Tuple[int, ...], str, *Tuple[str, ...]] # Error
322+
x: Array[int, str, bool] # Ts1 = ???, Ts2 = ???
324323

325324
Type Concatenation
326325
------------------
@@ -361,71 +360,36 @@ Normal ``TypeVar`` instances can also be prefixed and/or suffixed:
361360
z = prefix_tuple(x=0, y=(True, 'a'))
362361
# Inferred type of z is Tuple[int, bool, str]
363362

364-
Unpacking a Tuple Type
365-
----------------------
363+
Unpacking Tuple Types
364+
---------------------
366365

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.
366+
We mentioned that a ``TypeVarTuple`` stands for a tuple of types.
367+
Since we can unpack an ``TypeVarTuple``, for consistency, we also
368+
allow unpacking a tuple type. As we shall see, this also enables a
369+
number of interesting features.
370370

371-
Unpacking a Concrete Tuple Type
372-
'''''''''''''''''''''''''''''''
371+
372+
Unpacking Concrete Tuple Types
373+
''''''''''''''''''''''''''''''
373374

374375
Unpacking a concrete tuple type is analogous to unpacking a tuple of
375376
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]
377+
equivalent to ``Tuple[int, bool, bool, str]``.
394378

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]``.
398-
399-
Unpacking an Unbounded Tuple Type
400-
'''''''''''''''''''''''''''''''''
379+
Unpacking Unbounded Tuple Types
380+
'''''''''''''''''''''''''''''''
401381

402382
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
383+
That is, ``*Tuple[int, ...]`` remains ``*Tuple[int, ...]``; there's no
384+
simpler form. This enables us to specify types such as ``Tuple[int,
385+
*Tuple[str, ...], str]`` - a tuple type where the first element is
386+
guaranteed to be of type ``int``, the last element is guaranteed to be
387+
of type ``str``, and the elements in the middle are zero or more
388+
elements of type ``str``. Note that ``Tuple[*Tuple[int, ...]]`` is
389+
equivalent to ``Tuple[int, ...]``.
390+
391+
Unpacking unbounded tuples is also useful in function signatures where
392+
we don't care about the exact elements and don't want to define an
429393
unnecessary ``TypeVarTuple``:
430394

431395
::
@@ -444,25 +408,26 @@ unnecessary ``TypeVarTuple``:
444408
process_batch_channels(z) # Error: Expected Channels.
445409

446410

447-
We can also pass a ``Tuple[int, ...]`` wherever a ``Tuple[*Ts]`` is
411+
We can also pass a ``*Tuple[int, ...]`` wherever a ``*Ts`` is
448412
expected. This is useful when we have particularly dynamic code and
449-
cannot infer the precise number of dimensions or the precise types for
413+
cannot state the precise number of dimensions or the precise types for
450414
each of the dimensions. In those cases, we can smoothly fall back to
451415
an unbounded tuple:
452416

453417
::
454418

419+
y: Array[*Tuple[Any, ...]] = read_from_file()
420+
455421
def expect_variadic_array(
456422
x: Array[Batch, *Shape]
457423
) -> None: ...
458424

425+
expect_variadic_array(y) # OK
426+
459427
def expect_precise_array(
460428
x: Array[Batch, Height, Width, Channels]
461429
) -> None: ...
462430

463-
y: Array[*Tuple[Any, ...]] = read_from_file()
464-
465-
expect_variadic_array(y) # OK
466431
expect_precise_array(y) # OK
467432

468433
``Array[*Tuple[Any, ...]]`` stands for an array with an arbitrary
@@ -473,10 +438,23 @@ is bound to ``Tuple[Any, ...]``. In the call to
473438
``Width``, and ``Channels`` are all bound to ``Any``.
474439

475440
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``.
441+
explicitly marking the code as unsafe (by using ``y: Array[*Tuple[Any,
442+
...]]``). Otherwise, users would face noisy errors from the type
443+
checker every time they tried to use the variable ``y``, which would
444+
hinder them when migrating a legacy code base to use ``TypeVarTuple``.
445+
446+
Multiple Unpackings in a Tuple: Not Allowed
447+
'''''''''''''''''''''''''''''''''''''''''''
448+
449+
As with `TypeVarTuples <Multiple Type Variable Tuples: Not
450+
Allowed_>`_, only one unpacking may appear in a tuple:
451+
452+
453+
::
454+
455+
x: Tuple[int, *Ts, str, *Ts2] # Error
456+
y: Tuple[int, *Tuple[int, ...], str, *Tuple[str, ...]] # Error
457+
480458

481459
``*args`` as a Type Variable Tuple
482460
----------------------------------
@@ -508,18 +486,19 @@ or suffixes of the variadic argument list. For example:
508486
::
509487

510488
# os.execle takes arguments 'path, arg0, arg1, ..., env'
511-
def execle(path: str, *args: *Tuple[*Ts, Mapping[str, str]]) -> None: ...
489+
def execle(path: str, *args: *Tuple[*Ts, Env]) -> None: ...
512490

513-
Note this this is different to
491+
Note that this is different to
514492

515493
::
516494

517-
def execle(path: str, *args: *Ts, env: Mapping[str, str]) -> None: ...
495+
def execle(path: str, *args: *Ts, env: Env) -> None: ...
518496

519497
as this would make ``env`` a keyword-only argument.
520498

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``:
499+
Using an unpacked unbounded tuple is equivalent to the PEP 484
500+
behavior [#pep-484-args]_ of ``*args: int``, which accepts zero or
501+
more values of type ``int``:
523502

524503
::
525504

@@ -587,10 +566,10 @@ Type variable tuples can also be used in the arguments section of a
587566
def __init__(
588567
self,
589568
target: Callable[[*Ts], None],
590-
args: Tuple[*Ts]
591-
): ...
569+
args: Tuple[*Ts],
570+
) -> None: ...
592571

593-
def func(arg1: int, arg2: str): ...
572+
def func(arg1: int, arg2: str) -> None: ...
594573

595574
Process(target=func, args=(0, 'foo')) # Valid
596575
Process(target=func, args=('foo', 0)) # Error
@@ -621,7 +600,7 @@ the function:
621600
def foo(*args: *Tuple[int, *Ts, T]) -> Tuple[T, *Ts]: ...
622601

623602
Behaviour when Type Parameters are not Specified
624-
''''''''''''''''''''''''''''''''''''''''''''''''
603+
------------------------------------------------
625604

626605
When a generic class parameterised by a type variable tuple is used without
627606
any type parameters, it behaves as if the type variable tuple was
@@ -654,7 +633,7 @@ This also works in the opposite direction:
654633

655634
takes_specific_array(z)
656635

657-
(For details, see the section on `Unpacking an Unbounded Tuple Type`_.)
636+
(For details, see the section on `Unpacking Unbounded Tuple Types`_.)
658637

659638
This way, even if libraries are updated to use types like ``Array[Height, Width]``,
660639
users of those libraries won't be forced to also apply type annotations to
@@ -729,7 +708,7 @@ Normal ``TypeVar`` instances can also be used in such aliases:
729708
Foo[str, int]
730709
# T bound to float, Ts to Tuple[()]
731710
Foo[float]
732-
# T bound to Any, Ts to an arbitrary number of Any
711+
# T bound to Any, Ts to an Tuple[Any, ...]
733712
Foo
734713

735714
Overloads for Accessing Individual Types
@@ -810,8 +789,8 @@ otherwise imply. Also, we may later wish to support arguments that should not be
810789

811790
We therefore settled on ``TypeVarTuple``.
812791

813-
Unspecified Type Parameters: Tuples vs TypeVarTuples
814-
----------------------------------------------------
792+
Unspecified Type Parameters: Tuple vs TypeVarTuple
793+
--------------------------------------------------
815794

816795
In order to support gradual typing, this PEP states that *both*
817796
of the following examples should type-check correctly:
@@ -1470,6 +1449,8 @@ References
14701449
14711450
.. [#dan-endorsement] https://mail.python.org/archives/list/python-dev@python.org/message/HTCARTYYCHETAMHB6OVRNR5EW5T2CP4J/
14721451
1452+
.. [#pep-484-args] https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values
1453+
14731454
Copyright
14741455
=========
14751456

0 commit comments

Comments
 (0)