Hacker News new | past | comments | ask | show | jobs | submit login
Type hints cheat sheet (Python 3) (mypy.readthedocs.io)
51 points by sytelus on Dec 12, 2018 | hide | past | favorite | 18 comments



I've been using mypy for a while now and I love it!

I added mypy type annotations to a bunch of old projects and it found some bugs no one was aware of right away.

I love the support I get from mypy within the editor. It works flawlessly on my Linux machine with VSCode. It's quite good at inferring types as well. In most cases it's enough to annotate function parameters and return types. Mypy warns you in case it cannot infer the type for an item.

As of today I add mypy to every project that grows a certain size/importance. I think the optional typing approach is great. I usually start prototyping/modelling with few type annotations and gradually add more of them as the code stabilizes and end up with a fully typed solid piece of software.

I'm also excited about the benefits mypy/typing brings to the table in the area of compiled Python:

Cython is already able to utilize Python type annotations to compile pure Python code:

https://cython.readthedocs.io/en/latest/src/tutorial/pure.ht...

mypyc is another approach:

https://github.com/mypyc/mypyc

Nutika wants to utilize Python type annotations as well:

https://github.com/Nuitka/Nuitka

I guess there are more.

I think sooner or later we will have single file binaries compiled from pure Python that run with much improved performance.


Can you elaborate on the hidden bugs annotating old projects revealed?


I've used Python type hints for awhile now and have some mixed reviews.

First, the good: the extra safety and autocomplete functionality is very helpful once you have everything up and running. I feel a lot better about the type-safety of my code when I have a static typing mechanism; even if it's optional, I still get to use it. Also, it's very helpful that you can further specify optional types, container types, or Callable types.

Now, the bad:

* While you can specify a type as "Optional", there isn't (unless it's been recently added) a way for any of the tooling that consumes these type hints to actually enforce that types that you don't specify as Optional are non-Optional. Python makes it pretty hard to get None, compared to the relative ease of Ruby's nils and Java's null references, but I won't be fooled again.

* It feels weird to have to explicitly import things from `typing`. Is there an actual dummy class called `typing.Any` that will magically pass a type comparison against any other Python object? I dunno, it feels weird to import typing metadata the same way as actual code.

* If you use any third-party libraries, it is a serious pain to import the actual class that you want to use as a type annotation. It's either impossible or nigh-impossible with boto3 in particular.


Is there an actual dummy class called `typing.Any` that will magically pass a type comparison against any other Python object?

There is an object called "typing.Any". It's a singleton, immutable, un-subclassable sentinel object for static type checking tools to recognize and handle. Runtime type checkers cannot work with it; it actually overrides both the __instancecheck__ and the __subclasscheck__ special methods to raise exceptions and forbid attempts to use runtime isinstance() or issubclass() checks against Any.


So maybe this is because of the type of projects I work on, or maybe my use of the language, but type errors are really rare in my code and show up almost instantly. The main source of them is data from external APIs where a None was returned where an object was expected. Second biggest source is when parsing XML and a None results from some node not having the expected children. I feel like type checking would give me almost no benefit aside from the very rare instance where I might make a quick code correction without testing it and have it blow up because I mixed up the order of parameters. What am I missing?


I can't answer what you're missing as I'm missing it too. Type annotations have seemed to me as useful documentation. If they're strictly enforced, it might make it easier for a new coder to interface with unfamiliar code...but if it was designed well in the first place, duck typing should handle it and raise exceptions as appropriate.


Type hints are more about proving correctness and catching errors early. If your code expects ints and all of a sudden it gets floats there is probably something wrong somewhere else, and the type checker tells you about it since Python would probably just chug along with floats instead of ints.



I started using type hinting and I'm really loving it. Compared with Java and Scala, where I often feel like I'm in a typing straitjacket, it's really nice to add it gradually to a project as the code base grows. And props to the IntelliJ people; PyCharm makes great use of the type hinting for autocomplete and warning about possible errors.


what's the difference between list and List, dict and Dict and Mapping?


Suppose you want to indicate that a particular variable is a list of int. You might write "list[int]" to indicate that. But try that in a Python interpreter and you'll get an error -- "list[int]" attempts to subscript the list class object, which doesn't work.

So typing.List exists to be a subscriptable object you can use when annotating, and "typing.List[int]" works. Same for the other names.


Thanks, I tried, and indeed:

list[int] TypeError: 'type' object has no attribute '__getitem__'

couldn't they just implement __getitem__ on the existing list class instead of creating semantic duplication?


The exact error you're going to get in a modern Python is:

    TypeError: 'type' object is not subscriptable
That's because "list" refers to the class object, which is not an instance of list; it's an instance of type. Implementing __getitem__ on list (which is already implemented!) will not help. Try it yourself:

    class MyClass:
        def __getitem__(self, key):
            return f"You asked for {key}"
Now try "MyClass[int]". You'll get the same error: "TypeError: 'type' object is not subscriptable". Class objects in Python are instances of type, so __getitem__ would have to be implemented on type in order to make this work. Which would in turn make it work on any type in Python, not just those which are supposed to represent collections/mappings.

The typing module's solution of sentinel objects to stand in for collection/mapping types, supporting subscripting for annotating the types of contents, is probably a better solution.


Understood. They could just allow __getitem__ on types to avoid semantic duplications.


List, Dict can be enriched with the type of objects they contain: e.g. List[int] or Dict[str, str].

Mapping is a type hint for any object that implements the __getitem__ magic method (i.e. you can do `foo[bar]`).


I find it weird how the variable type is between the name and value. I’m sure there is a well thought out valid reason though


This is something I was introduced to when learning Rust. I've grown to like it as I now read declarations such as:

let x: int32 ...

as "let x be a 32 bit integer ...".


I think it's just the nature of how it expanded from type hinting.

That is, originally, you were simply hinting at the type of the variable through "pi: float" rather than declaring it. In that standalone context, the format makes sense to me.




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

Search: