- 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 ˊ~ω~ˋ