
Another concern I have is the over specification of types. I have seen many examples of, e.g. func(x: int, y: float, stuff: List(int]): but very few of: func(x: SupportsInt, y: SupportsFloat, stuff: Sequence[SupportsInt]): (or even Iterable[int]) Is that even the right thing to do to get generic number types? How do I specify a type that could be any number type (float, int, Fraction, Decimal, numpy.float32) ... I just spent a few minutes perusing the typing module and MyPy docs, and didn't find a discussion of that. But I'd really love to see the community as a whole start with more generic types in examples, and be clear that the concrete types should be used only when necessary -- even the typing module docs use a lot of concrete types in the examples. I think this is an issue for two reasons: 1) Folks learn from examples more than instruction -- people are very likely to follow the first example they see that seems to do the job. 2) as mentioned in this thread, library authors are being asked to type hint their libraries. I think it will be all too common for that type hinting to be more specific than required. For the most part, that won't cause any real issues right away, but as soon as someone uses that lib in a large project that enforces static type checking, it's could get ugly. -CHB On Tue, Nov 30, 2021 at 1:37 PM Paul Moore <p.f.moore@gmail.com> wrote:
On Tue, 30 Nov 2021 at 19:07, Brett Cannon <brett@python.org> wrote:
On Tue, Nov 30, 2021 at 9:09 AM Steven D'Aprano <steve@pearwood.info>
wrote:
On Tue, Nov 30, 2021 at 02:30:18PM +0000, Paul Moore wrote:
And to be clear, it's often very non-obvious how to annotate something - in https://github.com/pfmoore/editables I basically gave up because I couldn't work out how to write a maintainable annotation for an argument that is "a Path, or something that can be passed to the Path constructor to create a Path" (it's essentially impossible without copy/pasting the argument annotation for the Path constructor).
You're after https://docs.python.org/3/library/os.html?highlight=pathlike#os.PathLike: `str | PathLike[str]` (if you're only accepting string paths).
Well, it's not really. What I'm after, as I stated, is "anything that can be passed to the Path constructor". Yes, str | PathLike[str] is probably close enough (although why is it OK for me to prohibit bytes paths?) but that's what I mean about copying the Path constructor's annotations. If Path changes, I have to change my code.
This is a very common idiom:
def f(p: ???): p = Path(p) ...
Why isn't it correspondingly straightforward to annotate?
If PathLike[str] included str, then it would be a lot easier. It's not at all obvious to me why it doesn't (well, that's not entirely true - it's because PathLike is an ABC, not a protocol, and it's not intended to define "the type of objects that the Path constructor takes"). It would still not be documented anywhere, though.
I thought that type inference was supposed to solve that sort of problem? If the typechecker can see that an argument is passed to the Path constructor, it should be able to infer that it must be the same types as accepted by Path.
I would change that "should" to "may". Python's dynamism makes inferencing really hard.
That's fair. That's why I think it should be straightforward for the user to explicitly say "this argument should accept the same types as pathlib.Path does". If inference can't do it automatically, and the user can't (easily) let the checker know that it's OK to do it, then we're left with no easy way to express a very common pattern.
Aside: I'm a little disappointed in the way the typing ecosystem has developed. What I understood was that we'd get type inference like ML or Haskell use, so we wouldn't need to annotate *everything*, only the bits needed to resolve ambiguity. But what we seem to have got is typing like C, Pascal and Java, except gradual. Am I being unreasonable to be disappointed? I'm not a heavy mypy user, I just dabble with it occasionally, so maybe I've missed something.
It really depends on the code base. Type checkers can make guesses based on the code they have available to them, but that only works if the usage is really clear and the dynamic nature of the code doesn't make things murky. For instance, look at open() and how whether you opened a file with `b` or not influences whether the object's methods return strings or bytes. What would you expect to be inferred in that case if you didn't annotate open() with overrides to specify how its arguments influence the returned object?
Personally, I'd be quite happy leaving open() as duck typed. I see this as what Steven was getting at - the "typing ecosystem" has moved into a situation where it's acknowledged that some typing problems are really hard, due to Python's dynamism, and yet there's still a drive to try to express such highly dynamic type constraints statically. And worse still, to insist that doing so is somehow necessary.
Whatever happened to "practicality beats purity", and typing being "gradual"? Surely annotating everything except open() is practical and gradual?
Paul _______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-leave@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/YXVXN22T... Code of Conduct: http://python.org/psf/codeofconduct/