> the lack of documentation

If the code base expects flexibility, trusting documentation is the last thing you'd want to do. I know some people live and die by the documentation, but that's just a bad idea when duck typing or composition is heavily used for instance, and documentation should be very minimal in the first place.

When a function takes a myriad of potential input, "can this function do X" is an answer you get by reading the function or the tests, not the prose on how it was intended 10 years ago or how some other random dev thinks it works.

Documentation doesn’t have to be an essay. A simple, automatically generated reference with proper types goes a long way to tell me „it can do that“ as opposed to „maybe it works lol“. That’s not the level of engineering quality I’m going for in my work.

This whole discussion is about how you might not want to be listing every single types a function accepts. I also kinda wonder how you automatically generate that for duck typing.

Generally using the Protocol[1] feature

    from typing import Protocol

    class SupportsQuack(Protocol):
        def quack(self) -> None: ...
This of course works with dunder methods and such. Also you can annotate with @runtime_checkable (also from typing) to make `isinstance`, etc work with it

[1]: https://typing.python.org/en/latest/spec/protocol.html

You're then creating a Protocol for every single function that could rely on some duck typing.

Imagine one of your function just wants to move an iterator forward, and another just wants the current position. You're stuck with either requiring a full iterator interface when only part of it is needed or create one protocol for each function.

In day to day life that's dev time that doesn't come back as people are now spending time reading the protocol spaghetti instead of reading the function code.

I don't deny the usefulness of typing and interfaces in stuff like libraries and heavily used common components. But that's not most of your code in general.

For the collections case in particular, you can use the ABCs for collections that exist already[1]. There's probably in your use case that satisfies those. There's also similar things for the numeric tower[2]. SupportsGE/SupportsGT/etc should probably be in the stdlib but you can import them from typeshed like so

    from __future__ import annotations

    from typing import TYPE_CHECKING

    if TYPE_CHECKING:
        from _typeshed import SupportsGT
---

In the abstract sense though, most code in general can't work with anything that quack()s or it would be incorrect to. The flip method on an penguin's flipper in a hypothetical animallib would probably have different implications than the flip method in a hypothetical lightswitchlib.

Or less by analogy, adding two numbers is semantically different than adding two tuples/str/bytes or what have you. It makes sense to consider the domain modeling of the inputs rather than just the absolute minimum viable to make it past the runtime method checks.

But failing that, there's always just Any if you legitimately want to allow any input (but this is costly as it effectively disables type checking for that variable) and is potentially an indication of some other issue.

[1]: https://docs.python.org/3.14/library/collections.abc.html

[2]: https://docs.python.org/3/library/numbers.html

> You're then creating a Protocol for every single function that could rely on some duck typing.

No, you are creating a Protocol (the kind of Python type) for every protocol (the descriptive thing the type represents) that is relied on for which an appropriate Protocol doesn’t already exist. Most protocols are used in more than one place, and many common ones are predefined in the typing module in the standard library.

[deleted]