@@ -543,3 +543,143 @@ Try `mypyc`; it can compile your Python, giving a 2-5x speedup on a fully typed
543543- [ Awesome Python Typing] ( https://github.com/typeddjango/awesome-python-typing ) : A curated list of links to Python typing related things
544544- [ Adam Johnson's Typing series] ( https://adamj.eu/tech/tag/mypy/ )
545545- [ MyPy's cheat sheet] ( https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html )
546+
547+ ---
548+
549+ ## Examples
550+
551+ Following are some examples.
552+
553+ ---
554+
555+ ## What's the best annotation for this function?
556+
557+ ``` python
558+ def all_upper (values ):
559+ return [v.upper() for v in values]
560+
561+
562+ items = [" one" , " two" ]
563+ result = all_upper(items)
564+ ```
565+
566+ ---
567+
568+ ## Attempt 1: explicit values
569+
570+ ``` python
571+ def all_upper (values : list[str ]) -> list[str ]:
572+ return [v.upper() for v in values]
573+
574+
575+ items = [" one" , " two" ]
576+ result = all_upper(items)
577+ ```
578+
579+ ---
580+
581+ ## What about different container?
582+
583+ ``` python
584+ def all_upper (values : list[str ]) -> list[str ]:
585+ return [v.upper() for v in values]
586+
587+
588+ items = (" one" , " two" )
589+ result = all_upper(items) # ❌
590+ ```
591+
592+ ---
593+
594+ ## Attempt 2: Protocol
595+
596+ ``` python
597+ def all_upper (values : Sequence[str ]) -> list[str ]:
598+ return [v.upper() for v in values]
599+
600+
601+ items = (" one" , " two" )
602+ result = all_upper(items)
603+ ```
604+
605+ ---
606+
607+ ## Details
608+
609+ This is fairly common: Use a Protocol for input arguments, and be as exact as possible on output arguments!
610+
611+ In fact, _ try never to return a Protocol_ . You want the type system to track _ actual_ types.
612+
613+ ---
614+
615+ ## Bad use of Protocol
616+
617+ ``` python
618+ from collections.abc import Sequence
619+ from typing import Any, reveal_type
620+ import copy
621+
622+
623+ def copy_sequence (seq : Sequence[Any]) -> Sequence[Any]:
624+ return copy.copy(seq)
625+
626+
627+ a = [" 1" , " 2" ]
628+ b = copy_sequence(a)
629+ reveal_type(b) # Sequence[Any]
630+ ```
631+
632+ As a reader, the type of ` b ` is obvious: it's a ` list[str] ` . But typing can't see that.
633+
634+ ---
635+
636+ ## Better
637+
638+ ``` python
639+ from collections.abc import Sequence
640+ from typing import Any, reveal_type
641+ import copy
642+
643+
644+ def copy_sequence[T: Sequence[Any]](seq: T) -> T:
645+ return copy.copy(seq)
646+
647+
648+ a = [" 1" , " 2" ]
649+ b = copy_sequence(a)
650+ reveal_type(b) # list[str]
651+ ```
652+
653+ ---
654+
655+ ## Smarter return types
656+
657+ You want the return type to be as accurate as possible. Use overloads if the type depends on the arguments in a non-trivial way (not passed through).
658+
659+ ``` python
660+ def call (* args : str , quiet : bool = False ) -> str | None :
661+ # Logic would go here
662+ if quiet:
663+ return f " result of { args} "
664+ return None
665+
666+
667+ call(" echo" , " hi" , quiet = True ).strip() # ❌ Can't call on None
668+ ```
669+
670+ ---
671+
672+ ## Smarter return types
673+
674+ ``` python
675+ @overload
676+ def call (* args : str , quiet : Literal[False ] = ... ) -> None : ...
677+
678+
679+ @overload
680+ def call (* args : str , quiet : Literal[True ]) -> str : ...
681+
682+
683+ def call (* args : str , quiet : bool = False ) -> str | None :
684+ " See above"
685+ ```
0 commit comments