DarkMatter in Cyberspace
  • Home
  • Categories
  • Tags
  • Archives

Typing System in Python 3


Install mypy with conda install -c anaconda-platform mypy, vim plugin 'w0rp/ale' (asynchronous lint engine, which embed mypy into vim) and 'python-mode/python-mode' (see dsnot Python IDE based on vim).

The following codes demonstrates how mypy find typing incompatibility before running the code:

$ cat << EOF > test.py
from typing import Iterable
def mean(items: Iterable) -> float:
    return sum(items) / len(items)
EOF

$ mypy test.py
test.py:5: error: Argument 1 to "len" has incompatible type Iterable[Any]; expected "Sized"

Another example based on codes in chapter 10 of "Functional Python Programming", 2nd edition by Steve Lott:

Save the following codes into typecheck.py:

from typing import (Callable, Iterable, Any, TypeVar, Dict, Iterator,
                    List, Tuple, cast)
from functools import reduce
from operator import add
from collections import defaultdict
from itertools import groupby


T = TypeVar('T')


def map_reduce(mapf: Callable, reducef: Callable, source: Iterable) -> Any:
    return reduce(reducef, map(mapf, source))


def mr2(mapf: Callable[[T], T], reducef: Callable[[T, T], T],
        source: Iterable[T]) -> T:
    return reduce(reducef, map(mapf, source))


data = [1, 2, 3, 5]
res = map_reduce(lambda x: x * 10, add, data)
print(res)
res = mr2(lambda x: x * 10, add, data)
print(res)


K = str  # means "key"
D = Tuple[K, float]
inp: List[D] = [
    ('4', 6.1), ('1', 4.0), ('2', 8.3), ('2', 6.5), ('1', 4.6),
    ('2', 6.8), ('3', 9.3), ('2', 7.8), ('2', 9.2), ('4', 5.6),
    ('3', 10.5), ('1', 5.8), ('4', 3.8), ('3', 8.1), ('3', 8.0),
    ('1', 6.9), ('3', 6.9), ('4', 6.2), ('1', 5.4), ('4', 5.8)]


def partition(source: Iterable[D],
              key: Callable[[D], K] = lambda x: cast(K, x)
              ) -> Iterable[Tuple[K, List[float]]]:
    pd: Dict[K, List[float]] = defaultdict(list)
    for item in source:
        pd[key(item)].append(item[1])
    for k in sorted(pd):
        yield k, pd[k]


for key, group_iter in partition(inp, key=lambda x: x[0]):
    print(key, list(group_iter))


def partition_s(source: Iterable[D],
                key: Callable[[D], K] = lambda x: cast(K, x)
                ) -> Iterable[Tuple[K, Iterator[D]]]:
    return groupby(sorted(source, key=key), key)


res = partition_s(inp, key=lambda x: x[0])
for key, groupIter in partition_s(inp, key=lambda x: x[0]):
    print(key, list(groupIter))

If you change T = TypeVar('T') to T = str, there will be an 'incompatible type ...error marked on functionmr2`.

The following codes shows the function of typing.cast:

>>> from typing import cast
>>> cast(float, 3)
3
>>> type(cast(float, 3))
int

It returns the argument (here it's 3) itself. And tell the type checker "I am a float variable". While at runtime the Python interpreter will simply ignore the cast function and treat 3 as an integer.



Published

Jul 25, 2018

Last Updated

Sep 10, 2018

Category

Tech

Tags

  • python 136
  • type 1

Contact

  • Powered by Pelican. Theme: Elegant by Talha Mansoor