2. ‣ 12+ лет опыта, 7 лет с Python, 6 с JS
‣ Работал в oDesk, Helios, 42cc.
‣ Соорганизатор PyCon Ukraine, KyivJS
‣ CTO в CartFresh
Обо мне
3. ‣ Стартап по доставке продуктов на дом
‣ Работаем как CartFresh (Boston, US) и ZAKAZ.UA
(Киев, Днепр, Одесса, Харьков)
‣ Apache CouchDB, Apache Solr, Redis
‣ python back-end
CartFresh
4. Эта презентация не о
‣ автогенерации кода
‣ поиске серебряной пули
‣ проверке типов в рантайме
‣ статически типизированным питоне
6. ‣ Немного зачем это надо
‣ Как это выглядит
‣ Тулы и как можно пользоваться на практике
Содержание
8. Пусть в некой деревне живёт брадобрей, который
бреет тех и только тех, которые не бреются сами.
Бреет ли брадобрей сам себя?
Парадокс Рассела
9. ‣ В 1908 Russell & Whitehead доставили “"ramified" theory of types”
‣ В 1920-х Leon Chwistek and Frank P. Ramsey доставили "simple
type theory”
‣ 1940 Alonzo Church "A Formulation of the Simple Theory of Types”
‣ 1972 Girard–Reynolds discovered System F (polymorphic lambda
calculus)
История
10. ‣ Пацаны обратили внимание, что у простой теории
типов есть интересные свойства и может быть
просто расширена до поддержки Декартового
произведения и дизъюнктного объединения
‣ Поэтому простую теорию типов используют в
дизайне языков программирования
‣ А System F помогла улучшила простую теорию типов
и такое полезное свойство, как полиморфизм
Теория
12. ‣ Python will remain a dynamically typed language, and
the authors have no desire to ever make type hints
mandatory, even by convention
PEP 484
def f(x: str) -> str:
13. Gradual Typing
‣ Разработана в 2006 году Jeremy Siek и Walid Taha
‣ Идея состоит в том, чтобы позволить части кода
быть динамически типизированным, а части –
статически
14. Нафига
‣ Статическое описание типа аргументов и
возвращаемого значения функций упрощает чтение
кода и помогает формировать документацию
‣ Поможет обнаружить баги за меньшее количество
времени
‣ Поможет найти сложновоспроизводимые баги
быстрее
15. Напоминаю, чтение кода
‣ IBM 1989: 50% of the effort in accomplishing a task for the
programmer is towards understanding the system
‣ Bell Labs 1992: 60%-80% of their time understanding code,
20% as the developers gain experience with current
codebase
‣ National Research Council 1997 (Canada): over 25% of their
time either searching for or looking at code
‣ Peter Hallam 2006: 70% during personal experiment
‣ Microsoft 2007: 65% (survey)
16. Что было
‣ PyCharm умел делать статический анализ контекста
использования переменных. Мог трекать до 60%
случаев. Похоже на Facebook’s flow для JavaScript
‣ Prospector – смесь статического анализатора с PyLint
‣ In-house tools по анализу docstring etc.
18. Определение в контексте Python:
Предполагается, что тип – это множество значений и
множество функций, к которым можно применить эти
значения.
19. Gradual Typing
‣ Тип t1 консистентен с типом t2 если t1 это подтип t2
(но не наоборот!)
‣ Any консистентен со всеми типами (но не является
подтипом)
‣ Все типы являются подтипом Any
20. Отношение между подтипами
‣ Каждый тип является подтипом самого себя
‣ Множество значений уменьшается с увеличением
количества функций, которые работают с этим
подтипом
21. Типы vs Классы
Классы являются фабриками объектов, определенных
с помощью class . Класс – динамическая/runtime
концепция
22. Аннотации
‣ Аннотации типов являются опциональными
‣ Никак не влияют на выполнение
‣ lambda-функции не поддерживают аннотации
23. Синтаксис
def f(x: int) -> int:
return x + 1
print(f(1))
def f1(x: int) -> int:
y = "1" # type: int
return x + y
print (f(2))
24. Python 2
def embezzle(account, funds=1000000, *fake_receipts):
# type: (str, int, *str) -> None
"""Embezzle funds from account using fake
receipts."""
return None
print embezzle(1, 1000)
# hints11.py, line 9: Argument 1 to "embezzle" has
incompatible type "int";
expected "str"
25. Граф анализа
from typing import List, Any
def append_pi(lst: List[float]) -> None:
lst += [3.14]
append_seven(lst)
def append_seven(lst):
lst.append("7")
my_list = [1, 3, 5] # type: List[float]
append_pi(my_list)
print (my_list)
# [1, 3, 5, 3.14, '7']
27. Граф анализа
from typing import List, Any
def append_pi(lst: List[float]) -> None:
lst += [3.14]
def append_seven(lst):
lst.append("7")
append_pi(lst)
my_list = [1, 3, 5] # type: List[float]
append_seven(my_list)
print (my_list)
# [1, 3, 5, '7', 3.14]
28. Какие бывают
‣ Встроенные классы (int, bool etc.)
‣ Абстрактные классы
‣ Дополнительно из модуля typing: None , Any , Union ,
Tuple , Callable, Sequence, Dict
‣ Динамически вычисленные типы не работают
29. Алиасы
from typing import TypeVar, Iterable, Tuple
Url = str
def fetch(url: Url):
pass
T = TypeVar('T', int, float, complex)
def inproduct(v: Iterable[Tuple[T, T]]) -> T:
return sum(x*y for x, y in v)
print(inproduct(((1, 1.3),)))
# 1.3
30. Дженерики
‣ TypeVar – фабрика для создания
параметризированных дженериков, напр. AnyStr =
TypeVar('AnyStr', str, bytes)
‣ def concat(x: AnyStr, y: AnyStr) -> AnyStr –
ограничения на тип сразу на оба аргумента
31. Дженерики
from typing import TypeVar
AnyStr = TypeVar('AnyStr', str, bytes)
def concat(x: AnyStr, y: AnyStr) -> AnyStr:
return x + y
print(concat("_(*~", "*)_/"))
# _(*~*)_/
concat(b"_(*~", "*)_/")
# TypeError: string argument without an encoding
# hints4.py, line 17: Type argument 1 of "concat" has
incompatible value
"object"
32. Отношение между подтипами
from typing import List
class User(int):
pass
my_list = [1, 3, 5] # type: List[int]
my_list.append(User())
print(my_list)
# [1, 3, 5, 0]
my_list2 = [1] # type: List[User]
print (my_list2)
# hints2.py, line 14: List item 1 has incompatible
type "int"
33. Forward references
class Tree:
def __init__(self, left: Tree, right: Tree) -> None:
self.left = left
self.right = right
Это не будет работать
34. Forward references
class Tree:
def __init__(self, left: ‘Tree’, right: ‘Tree’) -> None:
self.left = left
self.right = right
Это не будет работать
35. Union
from typing import Union, Sequence
class Employee(str): pass
def employees(e: Union[Employee, Sequence[Employee]]) -> None:
if isinstance(e, Employee):
e = [e]
for _ in e:
print("Employee: {}".format(_))
employees(Employee("Max K"))
# Employee: Max K
employees([Employee("Max K"),
Employee("Dima Y")])
# Employee: Max K
# Employee: Dima Y
38. Переменные
x = [] # type: List[Employee]
x, y, z = [], [], [] # type: List[int], List[int], List[str]
x, y, z = [], [], [] # type: (List[int], List[int], List[str])
x = [
1,
2,
] # type: List[int]
39. Stub-files
‣ Расширения
‣ Third-party модули без типов
‣ Standard library модули
‣ Модули, которые должны поддерживать Python 2 и 3
‣ Модули, которые используют аннотации в другом
контексте