- What is (Static|Dynamic|Gradual) typing?
- Gradual Typing in Python
- Function annotations
- Type hints
- Type hinting syntax proposal
☺
☹
☺
☹
☹
def yolo(): return None + 42 yolo() # TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Any
type is involved (more on that later)
t1
is consistent with a type t2
x
and y
, and given the type of x
is consistent with the type of y
x
to y
in a type-safe manner
t1
is consistent with a type t2
if t1
is a
subclass of t2
. This relation is not symmetric.
Any
type is consistent with every type, but it is not
a subclass of every type.
Any
, which makes every type
consistent with Any
.
Any
is at the root of the type graph, like object
object
is not consistent with most types
Any
and object
mean "any type allowed" when annotating a function argument
Any
can be passed no matter what type is expected
Any
type never makes a type checker complain
Any
type
def say_hello(name : str = "Anon") -> None: # <- return value annotation # ^^^^^ ^ # | `- default value # `- parameter annotation print("Hello, {}".format(name))
def say_hello_to_everybody(*names : "An arbitrary number of names"): list(map(say_hello, names))
def
is preferred over lambda
def greet(name : str) -> str: return "Hello, {}".format(name)
☺
greet("Ada") # "Hello, Ada"
☹
greet(0xADA)
int # unbounded integer complex # complex number float # floating point number bool # boolean value str # unicode string bytes # 8-bit string
l = []
l
will be a list but the type of its elements is unknown
l = [] # type: List[int]
typing
module contains generic versions of concrete collection
types
from typing import List, Dict, Set, Tuple List[str] # list of str objects Dict[str, int] # dictionary from str to int Set[str] # set of str objects Tuple[int, int, int] # a 3-tuple of ints Tuple[int, ...] # a variable length tuple of ints
from typing import List l = [] # type: List[int]
☺
l = [1, 2, 3]
☹
l = [1, 2, "three"]
from typing import Dict d = {} # type: Dict[str, str]
☺
d = { "name": "Ada" }
☹
d = { "name": 0xADA }
from typing import Set s = set() # type: Set[int]
☺
s = {1, 2, 3}
☹
s = {"foo", "bar", "baz"}
from typing import Tuple t = () # type: Tuple[str, int]
☺
t = ("baz", 42)
☹
t = (42, "foo") # or t = ("baz", 42, "foo")
collections.abc
for duck typing
from typing import Mapping, MutableMapping, Sequence, MutableSequence Mapping[str, str] # a mapping from strings to strings MutableMapping[str, str] # a mutable mapping from strings to strings Sequence[int] # a sequence of integers MutableSequence[int] # a mutable sequence of integers
class Foo: def bar(self) -> str: return "baz" fooer = Foo()
☹
fooer.baz() # ^ # `- typos in method and property names result in type errors
Union
is
a type constructor
from typing import Union def mul(n : int, m : Union[str, int]): return n * m mul(42, 1) # 1 mul(42, '*') # "******************************************"
None
as an argument is a special case and is replaced by type(None)
Union[Union[int, str], float] == Union[int, str, float]
Union[str] == str
Union[str, str, int] == Union[str, int]
Any
is present, the union becomes an Any
TypeVar
for creating named generic types
from typing import TypeVar, Sequence, Iterator T = TypeVar('T') def dupe(xs : Sequence[T]) -> Iterator[T]: for x in xs: yield x yield x
from typing import Optional, TypeVar, Sequence T = TypeVar('T') def first(s : Sequence[T]) -> Optional[T]: # equivalent to Union[T, None] return s[0] if s else None
☹
x = first(["foo", "bar", "baz"]) x.lower() # must check for None before using
Set[int]
and Dict[str, int]
are concretions of
generic classes
A
and B
from typing import TypeVar, Generic A = TypeVar('A') B = TypeVar('B')
class Pair(Generic[A, B]): def __init__(self, x : A, y : B) -> None: self._value = (x, y,) @property def first(self) -> A: return self._value[0] @property def second(self) -> B: return self._value[1] def swap(self) -> Pair[B, A]: return Pair[B, A](self.second, self.first)
sp
has the type Pair[int, str]
a_pair = Pair[str, int]("yada", 42) another_pair = p.swap()
☹
a_string = "" # implies that x will be of type string a_string = another_pair.first
Callable
type includes the type of its arguments
and return value
Callable[[int, int], int]
Callable[..., int]
from typing import Callable, Iterable, TypeVar A = TypeVar('A') B = TypeVar('B', Iterable[A]) def typed_filter(f : Callable[[A], bool], xs : B) -> B: return filter(f, xs) def is_positive(x : int) -> bool: return x > 0
typed_filter(is_positive, {-3, -2, -1, 0, 1, 2, 3}) # {1, 2, 3}
☹
from operator import add typed_filter(add, {1, 2, 3})
Thank you ˊ~ω~ˋ