.title-slide # How You Can Benefit from Type Hints .right[Andrey Vlasovskikh] .right[JetBrains] .right[EuroPython 2015] --- .center[![PyCharm](media/pycharm-logo.png)] * I'm [@vlasovskikh](http://twitter.com/vlasovskikh) and [pirx.ru](http://pirx.ru/) * From St. Petersburg, Russia * I work for JetBrains * PyCharm: IDE for Python and Web development * I've been contributing to PEP 484: Type Hints * A part of Python 3.5 --- # Type Hints * *Type hints* — information provided by the user about types of function parameters, return values, class attributes, etc. * PEP 484 introduces a *formal definition* for type hints --- # What This Talk is About * Type hints: the motivation & how to get started * What can you get from type hints? * How to start using them? * What are the best practices? * Out of the scope * An overview of the type system of PEP 484 and the `typing` module --- # Quick Poll 1. Have you listened to the type hints talk by Guido van Rossum? 1. Have you looked into PEP 484: Type Hints? 1. Have you had a chance to play with type hints? --- # Type Hints Used to Be Informal * An example from the standard library `filter(function, iterable)` Construct an .highlight[iterator] from those elements of .highlight[iterable] for which .highlight[function] returns .highlight[true]. iterable may be either .highlight[a sequence], .highlight[a container which supports iteration], or .highlight[an iterator]. If function is .highlight[None], the identity function is assumed, that is, all elements of iterable that are false are removed. --- # PEP 484: Type Hints * Based on function annotations, Python 3.5 * Explicit is better than implicit from typing import * T = TypeVar('T') def filter(function: .highlight[Optional[Callable[[T], Any]]], iterable: .highlight[Iterable[T]]) -> .highlight[Iterator[T]]: ... * Gradual typing * Still dynamic typing, doesn't affect run-time * Everything is of type `Any` by default --- # The Main Benefit * Improved **readability** for both humans and tools * Documentation * More compact and easier to grasp than lengthy native language descriptions * Type checking and code completion * Type information is crucial for static code analysis --- .title-slide # Type Hints for Tools --- # The Tools * Mypy * The main inspiration for PEP 484 * PyCharm * Community Edition is free and open-source * PyCharm 4.5 has basic support for PEP 484 * 5.0 is coming this fall * And so on * Several others will support type hints soon * PEP 484 is very new --- # The Example: ElementTree * Standard `xml.etree.ElementTree` * Simple API for handling XML data * With our own type hints * Let's call it `etree` --- # What's Wrong Here? .python import etree element = etree.Element(b'div', {'width': 100}) print(etree.tostring(element)) --- # Exceptions * Cannot serialize `b'div'` and `100` .python >>> import etree >>> element = etree.Element(b'div', {'width': 100}) >>> print(etree.tostring(element)) Traceback (most recent call last): ... TypeError: cannot serialize b'div' (type bytes) --- # Add Type Hints * Start with a few function annotations .python from typing import Dict class Element: def __init__(self, tag: .highlight[str], attrib: .highlight[Dict[str, str]] = {}, **extra) -> .highlight[None]: ... * `typing.Dict` is a generic dictionary type * Redefines `__getitem__` for specifying types of keys and values --- # Type Checking * PyCharm .center[![](media/element-binary-div.png)] * Mypy .xml $ mypy a.py a.py: At top level: a.py, line 3: List item 1 has incompatible type "Tuple[str, int]" a.py, line 3: Argument 1 to "Element" has incompatible type "bytes"; expected "str" --- # Let's Annotate ElementTree's API * Most type hints are simple .python from typing import Any, Iterator def register_namespace(prefix: str, uri: str) -> None: ... def iselement(element: Any) -> bool: ... * Some hints use generics .python class Element: def iter(self, tag: str = None) -> 'Iterator[Element]': ... def itertext(self) -> Iterator[str]: ... --- # Type Inference * Tools can infer types in some cases * Follow assignments to variables * Return types of local functions .center[![](media/type-inference.png)] --- # Code Completion * Context-sensitive code completion * An analyzer can go deeper here than a type checker .center[![](media/code-completion.png)] --- .title-slide # Type Hints for Documentation --- # Docs are Often Too Wordy * The description from the docs * _etree.Comment(text=None)_ Comment element factory. This factory function creates a special element that will be serialized as an XML comment by the standard serializer. .highlight[The comment string can be either a **bytestring** or a Unicode string]. _text_ is a .hightlight[string] containing the comment string. Returns an .highlight[element instance] representing a comment. .python >>> print(etree.tostring(etree.Comment(b'foo'))) b"" --- # Docs with Type Hints * From the docstring using the Sphinx autodoc extension * _etree.Comment(text: .highlight[str]=None) → .highlight[etree.Element]_ Comment element factory. This function creates a special element which the standard serializer serializes as an XML comment. _text_ is the comment string. --- .title-slide # How to Create Type Hints --- # Type Hints for Your Public APIs
* **Annotate public APIs!** * Elements listed in `__all__` * The users of your library will thank you for that :) * Works very well for Erlang, TypeScript, etc. * [http://tinyurl.com/typehinting#23](http://tinyurl.com/typehinting#23) * You don't have to annotate everything * Type checkers can infer types --- # From Simple to Complex * Start with simple types * Simple types are often enough * Just use classes as types * Use collection types from `typing` * PEP 484 defines advanced types as well * Union types, generics, function types, etc. * You can always use `Any` if the type is tricky --- # Liberal vs Conservative * Be liberal in what you accept, and conservative in what you return from typing import Iterable, List def even(numbers: Iterable[int]) -> List[int]: return list(n for n in numbers if n % 2 == 0) * The `typing` module defines abstract collection types * `Mapping`, `Sequence`, `AbstractSet`, etc. --- # Type Hints in Your Code * Type hints in Python 3 function annotations * It's enough to `pip install` a library * Compatible with Python 3.5 * Python 3.2-3.4 require `typing` from PyPI * For Python 2 you can use Python stubs --- # Python Stubs * Files with the `*.pyi` extension and `...` instead of bodies * Read only by type checkers # xml/etree/ElementTree.pyi from typing import * class Element: def __init__(self, tag: str, attrib: Dict[str, str] = {}, **extra) -> None: ... def itertext(self) -> Iterator[str]: ... def Comment(text: str = None) -> Element: ... --- # Your Stubs for Third-Party Libraries * Put your local stubs somewhere on `sys.path` * E.g. in the `typehints` folder inside your project * Share your stubs with others * Send a pull request to the _typeshed_ repo * A shared collection of stubs for third-party libraries * Motivation: a very successful DefinitelyTyped repo for TypeScript * [https://github.com/JukkaL/typeshed/](https://github.com/JukkaL/typeshed/) * Make a PyPI package for stubs * `pip install somelibrary-stubs` --- # Available Type Hints * Tools use stubs behind the scenes * Standard library stubs bundled with PyCharm * Our own legacy syntax for type hints * We are switching to PEP 484 * Clone the typeshed repo and use it * [https://github.com/JukkaL/typeshed/](https://github.com/JukkaL/typeshed/) * Search stub packages for libraries on PyPI --- .title-slide # In Conclusion --- # Try Type Hints! * How 1. Get Python 3.5 Beta or `typing` for Python 3.2-3.4 1. Get Mypy or PyCharm 1. Try using some type hints in your code * Feel free to ask any questions * [@vlasovskikh](http://twitter.com/vlasovskikh) and [pirx.ru](http://pirx.ru/) * The slides [http://tinyurl.com/typehinting](http://tinyurl.com/typehinting)