Better type at Python
7 November 2015
Rick Mak
Oursky
Rick Mak
Oursky
https://docs.python.org/3.5/whatsnew/3.5.html
Released on September 13, 2015, 2 months ago
New library modules introduced
typing: PEP 484 – Type Hints
The syntax introduced long ago, Dec-2006
PEP 3107 - Function Annotations
import typing
pip install typing
import sys class Person: def __init__(self, name, lang): self.name = name self.lang = lang def greeting(man): print(hello(man.name)) def hello(name = 'nobody'): return 'Hello' + name if __name__ == '__main__': p = Person(sys.argv[1], sys.argv[2]) greeting(p)
import sys class Person: def __init__(self, name: str, lang: str) -> None: self.name = name self.lang = lang def greeting(man: Person) -> None: print(hello(man.name)) def hello(name: str = 'nobody') -> str: return 'Hello' + name if __name__ == '__main__': p = Person(sys.argv[1], sys.argv[2]) greeting(p)
Dictionary
from typing import Dict def inc(d: Dict[str, int]) -> Dict[str, int]: for k in d.keys(): d[k] = d[k] + 1 return d print(inc({ 'a': 1, 'b': 2, 'c': 3 }))
Sequence and List
from typing import Sequence, List, TypeVar T = TypeVar('T') # Declare type variable def pick_odd(s: Sequence[T]) -> List[T]: len_ = len(s) list_ = [] # type: List for i in range(0, len_): if i % 2 == 1: list_.append(s[i]) return list_ print(pick_odd([0,1,2,3,4,5,6,7])) print(pick_odd('abcdefg'))
class Human: def __init__(self, father: 'Human' = None, mother: 'Human' = None) -> None: self.father = father self.mother = mother def make(self, couple: 'Human') -> 'Human': return Human(self, couple) print(Human())
pip install mypy-lang
Analyse a file without running it
(venv)$ mypy callee.py callee.py, line 7: Argument 1 to "hello" has incompatible type "int"; expected "str"
def hello(name='nobody'): """Say hello to a person :param name: string value :rtype: string value """ return 'Hello' + name
def hello(name: str = 'nobody') -> str: '''Say hello to a person ''' return 'Hello' + name
An *.pyi file that only have interface
def greeting(name: str) -> None: ... def hello(name: str) -> str: ...
Also useful for
- Package you can't change
- Legacy package you don't want to change
There is github repos hosting stub for stdlib
python/typeshed
You can use inspect to get back the annotation.
import inspect print(inspect.getfullargspec(inc).annotations) ''' { 'd': typing.Dict[str, int], 'return': typing.Dict[str, int] } ''' print(inspect.getfullargspec(Human.make).annotations) ''' { 'return': 'Human', 'couple': 'Human' } '''
i.e. You may abuse it to do type conversion or validation at runtime.
20