Typing recommendation: abstract input types, concrete return types?

I remember reading some blog post about experiences with using mypy in large code bases and how one should take abstract input types but be concrete with the return types, like so:

class MyClass(int): ...

def some_function(values: Sequence[str]) -> MyClass: ...

Is this indeed a recommendation? I can’t find the post anymore.

The short answer, like to almost every question in engineering, is “it depends.” The “recommendation” you mention is a good general rule of thumb, but it would just make your interface unnecessarily difficult if your follow it too rigidly.

If there’s one rule you must follow, it is to always think about the intent. Why do you want to take that input argument? If you take it only to run for on it, it’s better to take an Sequence than a concrete List. But what if you’re not sure, and the behaviour can change if you rewrite the function? Then take a more concrete type, to avoid people passing in the wrong thing.

The same applies to the return value. Why do you return it, and what do you expect people to do with it? Returning MyClass would be essential if the type has special meanings to the caller. But int could be the right choice here if you really just want the caller to treat the return value as an int, and MyClass exists only because it makes your implementation easier.

Typing is part of the interface. It’s all about what you want to express. And there’s not a one-fit-all rule for that.