Hacker News new | past | comments | ask | show | jobs | submit login

> mypy has no trouble understanding this, but it’s unfortunately not valid Python code. You can’t refer to Node within the Node class.

No, the workaround is to stringify "Node".

    class Node(Object):
        def add_sub(self, sub: 'Node'):
            ...

        def get_subs(self) -> Sequence['Node']:  #Or maybe 'Sequence[Node]'
works just fine. As of python3.7, this stringification is done by automatically under a from future import, and will eventually become the default, so the original code will be valid.

> This complexity helped drive the introduction of the auto keyword to C++. There are many situations where writing the type information isn’t workable. This is especially true when dealing with parametric container classes,

This is absolutely wrong! You cannot annotate a function as returning `auto` in C++. `auto` and its variants in other languages are useful for eliding redundant type declarations. Especially long ones that use generics/templates. `auto foo = MyContainer<Tuple<int, str>>();` or whatever is nice than having to double write the type declaration. But, in C++ or java, if you write a function that returns a Mycontainer<Tuple<int, str>>, you have to write that in the function.

This is an intentional choice: function declarations are your apis, and explicit and clear APIs are useful for human readers of your code. That's why you should annotate the public apis[0] even when you can have them be type inferred. Speaking of which, if you want type inference, check out pytype[1], it's like MyPy, but does do type inference on unannotated code. But you should still annotate your public apis. It serves as a sanity check that you aren't accidentally returning something you don't expect.

And of course, being familiar with the differences between iterables, iterators, sequences, containers, etc. is not a bad idea.

[0]: https://google.github.io/styleguide/pyguide.html#3191-genera...

[1]: https://github.com/google/pytype






"[...]You cannot annotate a function as returning `auto` in C++. `auto` and its variants in other languages are useful for eliding redundant type declarations. Especially long ones that use generics/templates. `auto foo = MyContainer<Tuple<int, str>>();` or whatever is nice than having to double write the type declaration. But, in C++ or java, if you write a function that returns a Mycontainer<Tuple<int, str>>, you have to write that in the function.[...]"

Maybe I'm misunderstanding something, but one can write a function auto foo() in C++ and the return type is inferred. Lambda functions infer the return type by default.


Yuck, apparently I missed this happening. Its still (I think) true in java, where you can't have a function return `var`.

You're correct about Java. It was an explicit decision that the only local variable's type declarations and lambda parameters may be inferred with `var`.

This excludes, as you mentioned, the return types of a function, its parameter's types, as well as the types of fields in a class.


It’s only true if you have the function body available for deduction. Headers/decls need types.

There's a great 5m lightning talk from Pycon 2019 explaining the difference between pytype and mypy[0]. It's great that there's different libraries approaching the problem from different angles. Speaking of which, I'm also curious to see how Facebook's Pyre[1] differs from the former two. I'm surprise there's isn't a comprehensive comparison of the 3 libraries yet.

[0] https://www.youtube.com/watch?v=yFcCuinRVnU&t=38m25s

[1] https://github.com/facebook/pyre-check


Pyre is similar to mypy, in that it:

1. Is gradually typed,

2. Doesn't infer types, and

3. Is strict, in that it doesn't allow operations that change types.

It was originally developed as a replacement for mypy that was faster and scaled better to very large codebases.


> This is absolutely wrong! You cannot annotate a function as returning `auto` in C++.

You can do that since C++14.


> But you should still annotate your public apis.

The good thing about inference (especially with a REPL) is you can write it without the annotation, and then use the inferred type (in Haskell, I usually find that when I resist the temptation to explicitly annotate types, the actual types are more general than I would have specified.)


In Haskell, I usually find the quality of error messages to be much worse without top-level annotations.

I agree with that, too. My usual practice with Haskell is leave types off to leverage the information gained from type inference (with the intent of annotating signatures when I'm done), but then tell Haskell what I'm thinking the types should be if things break with impenetrable error messages.

But my coding in Haskell is pretty much personal and toy projects; I like the approach, but it may not be ideal for coding in anger.


This is generally true with pytype as well, but questionable whether it's a good thing.

Inferred, loose parameter types are great, because while I think it's good to know the differences between iterator, generator, iterable, sequence, container, and so on, it's difficult, and inference will give you the loosest one. But with return values, the inferred type will be the tighest, in other words your function will return a Dict (or worse, a defaultdict) instead of a Mapping or MutableMapping. You almost always want a Mapping.


As well as pytype, you can use a separate tool to discover the correct annotations, then verify them and add them to your source code. There are a couple - MonkeyType, pyannotate and pytypes.



Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: