Isn't your first paragraph all about not knowing what argument types the function accepts just looking at its declaration, as it defeats the purpose of using a dynamic language?
Type hints supports generics and abstract interfaces, you use those to display what behaviour you are using within the function and then you try to do what you need in the function as dynamically as possible.
That is for library code, maybe it would be too cumbersome to try to do that for code with less reuse. I have never worked on a large python codebase that wasn't a library so I'm not sure what is best there.