I often find myself defining function args with list[SomeClass]
type and think “do I really care that it’s a list
? No, tuple
or Generator
is fine, too”. I then tend to use Iterable[SomeClass]
or Collection[SomeClass]
. But when it comes to str
, I really don’t like that solution, because if you have this function:
def foo(bar: Collection[str]) -> None:
pass
Then calling foo("hello")
is fine, too, because “hello” is a collection of strings with length 1, which would not be fine if I just used list[str]
in the first place.
What would you do in a situation like this?
I know that
Iterable
andCollection
aren’t the same. My point is, that if you useIterable[str]
orCollection[str]
as a more flexible alternative tolist[str]
you no longer have any type-hinting support protecting against passing in a plain string and you could end up with a subtle bug by unexpectedly looping over['f', 'o', 'o']
instead of['foo']
.Strings are just a pain… Common solution is a runtime guard or doc comment. Can maybe try an overload and annotate a string param with NoReturn and an @throws doc comment.
Been awhile since doing python, but even that might not work since string satisfies both overloads. I recall having issues with unions where types were not discrete. I may have solved by ordering the overloads differently so string is considered first, but again, its been awhile.
https://stackoverflow.com/questions/44912374/python-type-annotation-for-sequences-of-strings-but-not-for-strings