[Michael Cuthbert:]
> > I'm rather surprised though that the typing advantages of the pep have not
> > been emphasized enough.
[Chris Angelico]
> That would be because I personally don't use that kind of strict
> typing, so it's not something I'm really qualified to talk about.
> Would you like to write up a paragraph or two about it? I could
> incorporate it verbatim, if you like.
Sure!
* * *
Late-bound arg defaults also help with proper typing, especially for
established code-bases that are incrementally adding typing to their code. For
instance, take this untyped example that might take a list of musical pitches
and put them in a particular order:
def order_pitches(pitches=None):
if pitches is None:
pitches = []
... # do reordering referencing "pitches" a lot
pitches.sort(key=lambda p: (p.octave, p.name))
return pitches
When the editor moves to a typed version, something like this would seem
reasonable:
def order_pitches(pitches: list[Pitch]|None = None) -> list[Pitch]:
... # same code as above.
However, some type checkers (for instance, that of PyCharm 2022) will continue
to reveal the type as "list[Pitch]|None" even after type narrowing. (Mypy will
correctly type narrow in this example but not in code that checks for `if not
hasattr(pitches, '__iter__')` and in many other more complex examples).
In this case, authors sometimes need to resort to rewriting code with a new
variable name:
def order_pitches(pitches: list[Pitch]|None = None) -> list[Pitch]:
non_none_pitches: list[Pitch]
if pitches is None:
non_none_pitches = []
else:
non_none_pitches = cast(list[Pitch], pitches)
... # rest of code must be rewritten to use "non_none_pitches"
The typed definition also seems to imply that "None" is an acceptable calling
type for the function rather than just being a stand-in for an omitted call. A
type-checker will allow `order_pitches(None)` to pass, perhaps preventing later
refactoring to use a sentinel such as:
def order_pitches(pitches: list[Pitch]|MISSING = MISSING) -> list[Pitch]:
if pitches is MISSING:
pitches = []
...
With the PEP, the process of adding typing does not impact the code, nor imply
that "None" is a fine calling signature.
def order_pitches(pitches: list[Pitch] => []) -> list[Pitch]:
...
# pitches is always list[Pitch] and needs no narrowing
pitches.sort(...)
return pitches
* * *
It is true that the tools for automatic type-narrowing continue to get better
(in looking up code that broke the type-narrowing with a "no_none..." variable,
I found that 2 of 4 places I found where I had done this workaround two years
ago no longer needed it for either mypy or PyCharm), but there are still
numerous cases where the process of typing around a sentinel type that will be
replaced by the correct type for computing still unnecessarily exist.
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/[email protected]/message/3MCSLWZUQQTK6FQWTBTCQPUUTGIFKND4/
Code of Conduct: http://python.org/psf/codeofconduct/