Skip to content

Commit 9bbc727

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

File tree

1 file changed

+55
-81
lines changed

1 file changed

+55
-81
lines changed

Diff for: pep-0646.rst

+55-81
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

@@ -315,13 +316,6 @@ 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-
320-
::
321-
322-
x: Tuple[int, *Ts, str, *Ts2] # Error
323-
y: Tuple[int, *Tuple[int, ...], str, *Tuple[str, ...]] # Error
324-
325319
Type Concatenation
326320
------------------
327321

@@ -364,68 +358,33 @@ Normal ``TypeVar`` instances can also be prefixed and/or suffixed:
364358
Unpacking a Tuple Type
365359
----------------------
366360

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+
370366

371367
Unpacking a Concrete Tuple Type
372368
'''''''''''''''''''''''''''''''
373369

374370
Unpacking a concrete tuple type is analogous to unpacking a tuple of
375371
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]``.
398373

399374
Unpacking an Unbounded Tuple Type
400375
'''''''''''''''''''''''''''''''''
401376

402377
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
429388
unnecessary ``TypeVarTuple``:
430389

431390
::
@@ -444,25 +403,26 @@ unnecessary ``TypeVarTuple``:
444403
process_batch_channels(z) # Error: Expected Channels.
445404

446405

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
448407
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
450409
each of the dimensions. In those cases, we can smoothly fall back to
451410
an unbounded tuple:
452411

453412
::
454413

414+
y: Array[*Tuple[Any, ...]] = read_from_file()
415+
455416
def expect_variadic_array(
456417
x: Array[Batch, *Shape]
457418
) -> None: ...
458419

420+
expect_variadic_array(y) # OK
421+
459422
def expect_precise_array(
460423
x: Array[Batch, Height, Width, Channels]
461424
) -> None: ...
462425

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

468428
``Array[*Tuple[Any, ...]]`` stands for an array with an arbitrary
@@ -473,10 +433,21 @@ is bound to ``Tuple[Any, ...]``. In the call to
473433
``Width``, and ``Channels`` are all bound to ``Any``.
474434

475435
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+
480451

481452
``*args`` as a Type Variable Tuple
482453
----------------------------------
@@ -508,18 +479,19 @@ or suffixes of the variadic argument list. For example:
508479
::
509480

510481
# 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: ...
512483

513484
Note this this is different to
514485

515486
::
516487

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

519490
as this would make ``env`` a keyword-only argument.
520491

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``:
523495

524496
::
525497

@@ -587,10 +559,10 @@ Type variable tuples can also be used in the arguments section of a
587559
def __init__(
588560
self,
589561
target: Callable[[*Ts], None],
590-
args: Tuple[*Ts]
591-
): ...
562+
args: Tuple[*Ts],
563+
) -> None: ...
592564

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

595567
Process(target=func, args=(0, 'foo')) # Valid
596568
Process(target=func, args=('foo', 0)) # Error
@@ -621,7 +593,7 @@ the function:
621593
def foo(*args: *Tuple[int, *Ts, T]) -> Tuple[T, *Ts]: ...
622594

623595
Behaviour when Type Parameters are not Specified
624-
''''''''''''''''''''''''''''''''''''''''''''''''
596+
------------------------------------------------
625597

626598
When a generic class parameterised by a type variable tuple is used without
627599
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:
729701
Foo[str, int]
730702
# T bound to float, Ts to Tuple[()]
731703
Foo[float]
732-
# T bound to Any, Ts to an arbitrary number of Any
704+
# T bound to Any, Ts to an Tuple[Any, ...]
733705
Foo
734706

735707
Overloads for Accessing Individual Types
@@ -1470,6 +1442,8 @@ References
14701442
14711443
.. [#dan-endorsement] https://mail.python.org/archives/list/python-dev@python.org/message/HTCARTYYCHETAMHB6OVRNR5EW5T2CP4J/
14721444
1445+
.. [#pep-484-args] https://www.python.org/dev/peps/pep-0484/#arbitrary-argument-lists-and-default-argument-values
1446+
14731447
Copyright
14741448
=========
14751449

0 commit comments

Comments
 (0)