53
Мир Python: функционалим с помощью библиотек [email protected] @sapronovalex92 http://pynsk.ru vk.com/pynsk facebook.com/PyNskCom @py_nsk Александр Сапронов:

Мир Python функционалим с помощью библиотек

  • Upload
    pynsk

  • View
    253

  • Download
    5

Embed Size (px)

Citation preview

Page 1: Мир Python  функционалим с помощью библиотек

Мир Python: функционалим с помощью библиотек

[email protected]

@sapronovalex92

http://pynsk.ru

vk.com/pynsk

facebook.com/PyNskCom

@py_nsk

Александр Сапронов:

Page 2: Мир Python  функционалим с помощью библиотек

О чем сегодня?

● Зловещая болезнь “ФП”● Признаки болезни● Пилюли● Как лечить

2

Page 3: Мир Python  функционалим с помощью библиотек

Кто такой ФП и зачем

ФП - функциональное программирование

ФП подходит для задач:

3

Page 4: Мир Python  функционалим с помощью библиотек

Кто такой ФП и зачем

Где есть многопоточность:

ФП подходит для задач:

● Пока делаем запрос в Интернет - дробим числа● В одном потоке обновляем GUI, в другом счетчики● Алгоритмы “Разделяй и властвуй”

ФП - функциональное программирование4

Page 5: Мир Python  функционалим с помощью библиотек

Кто такой ФП и зачем

Где есть многопоточность:

ФП подходит для задач:

● Пока делаем запрос в Интернет - дробим числа● В одном потоке обновляем GUI, в другом счетчики● Алгоритмы “Разделяй и властвуй”

5

Page 6: Мир Python  функционалим с помощью библиотек

Кто такой ФП и зачем

Где есть многопоточность

ФП подходит для задач:

Где нужен DSL:● Конфигурации (yaml…)● Конфиги-зависимости (gem…)● Системы тестирования

6

Page 7: Мир Python  функционалим с помощью библиотек

Кто такой ФП и зачем

Где есть многопоточность

ФП подходит для задач:

Где нужен DSL

● А это почти все задачи

Где нет необходимости хранить сложное состояние

7

Page 8: Мир Python  функционалим с помощью библиотек

Кто такой ФП и зачем

Где есть многопоточность

ФП подходит для задач:

Где нужен DSLГде нет необходимости хранить сложное состояниеГде хитрая бизнес-логика

8

Page 9: Мир Python  функционалим с помощью библиотек

Признаки болезни

● Функции высшего порядка● Замыкания● Иммутабельность● Чистые функции● Ленивость● Хвостовая рекурсия● Алгебраические типы данных● Pattern mathing

9

Page 10: Мир Python  функционалим с помощью библиотек

Признаки болезни

● Функции высшего порядка● Замыкания● Иммутабельность● Чистые функции● Ленивость● Хвостовая рекурсия● Алгебраические типы данных● Pattern mathing

Узнаем про это

Лень, но и это посмотрим

А еще вот это

10

Page 11: Мир Python  функционалим с помощью библиотек

Пилюли

fn.py (https://github.com/kachayev/fn.py) Python - стандартные библиотеки

funcy (https://github.com/Suor/funcy)

hask (https://github.com/billpmurphy/hask)

11

Page 12: Мир Python  функционалим с помощью библиотек

fn.py - Алексей КачаевВозможности:

● Scala-style лямбды

● Персистентные структуры

● Бесконечные последовательности

● Каррирование

● map, filter, reduce (одинаковые для 2.*, 3.*)

● Много еще всякого

12

Page 13: Мир Python  функционалим с помощью библиотек

Pipe:

from fn import F, _from fn.iters import filter, range

func = F() >> (filter, _ < 6) >> sumassert func(range(10)) == 15

>>> from fn.func import curried>>> @curried... def sum5(a, b, c, d, e):... return a + b + c + d + e...>>> sum5(1)(2)(3)(4)(5)15>>> sum5(1, 2, 3)(4, 5)15

Каррирование

fn.py (Алексей Качаев, Киев)

13

Page 14: Мир Python  функционалим с помощью библиотек

fn.py (Алексей Качаев, Киев)

from fn import Stream

s = Stream() << [1,2,3,4,5]assert list(s) == [1,2,3,4,5]assert s[1] == 2assert list(s[0:2]) == [1,2]

s = Stream() << range(6) << [6,7]assert list(s) == [0,1,2,3,4,5,6,7]

def gen(): yield 1 yield 2 yield 3

s = Stream() << gen << (4,5)assert list(s) == [1,2,3,4,5]

from fn.monad import Option request = dict(url="face.png", mimetype="PNG")tp = Option \ .from_value(request.get("type", None)) .or_call(from_mimetype, request) .or_call(from_extension, request) .get_or("application/undefined")

# check "type" key first# or.. check "mimetype" key# or... get "url" and check extension

14

Page 15: Мир Python  функционалим с помощью библиотек

funcy (Александр Щепановский, Красноярск)

● Sequences● Collections● Functions● Decorators● Flow● String utils● Calculation● Type testing● Objects● Debugging● Primitives

Много готового кода, который хорошо написан

15

Page 16: Мир Python  функционалим с помощью библиотек

funcy (Александр Щепановский, Красноярск)

● Sequences● Collections● Functions● Decorators● Flow● String utils● Calculation● Type testing● Objects● Debugging● Primitives

Inspired by clojure, underscore and my own abstractions.

16

Page 17: Мир Python  функционалим с помощью библиотек

funcy (Александр Щепановский, Красноярск)

● Sequences● Collections● Functions● Decorators● Flow● String utils● Calculation● Type testing● Objects● Debugging● Primitives

Inspired by clojure, underscore and my own abstractions.

17

Page 18: Мир Python  функционалим с помощью библиотек

merge(coll1, coll2, coll3, ...)join(colls)merge_with(sum, dict1, dict2, ...)

funcy (Александр Щепановский, Красноярск)

walk(str.upper, {'a', 'b'}) # {'A', 'B'}walk(reversed, {'a': 1, 'b': 2}) # {1: 'a', 2: 'b'}walk_keys(double, {'a': 1, 'b': 2}) # {'aa': 1, 'bb': 2}walk_values(inc, {'a': 1, 'b': 2}) # {'a': 2, 'b': 3}

select(even, {1,2,3,10,20}) # {2,10,20}select(r'^a', ('a','b','ab','ba')) # ('a','ab')select_keys(callable, {str: '', None: None}) # {str: ''}compact({2, None, 1, 0}) # {1,2}

18

Page 19: Мир Python  функционалим с помощью библиотек

hask (Bill Murphy, New York City)

● Система типизации Hindley-Milner

● Легко создавать АТД● Pattern matching● Композиции функций● Каррирование● Ленивость● Иммутабельность● Много другого

hask - попытка привнести возможности

Haskell в Python

19

Page 20: Мир Python  функционалим с помощью библиотек

hask (Bill Murphy, New York City)

● Система типизации Hindley-Milner

● Легко создавать АТД● Pattern matching● Композиции функций● Каррирование● Ленивость● Иммутабельность● Много другого

hask - попытка привнести возможности

Haskell в Python

20

Page 21: Мир Python  функционалим с помощью библиотек

hask (Bill Murphy, New York City)

>>> L[1, 2, 3]L[1, 2, 3]

>>> my_list = ["a", "b", "c"]>>> L[my_list]L['a', 'b', 'c']

>>> L[(x**2 for x in range(1, 11))]L[1 ... ]

Ленивый список

@sig(H/ int >> int >> int)def add(x, y): return x + y

Типизация

>>> from hask import _t

>>> _t(1)int

>>> _t(Just("soylent green"))(Maybe str)

>>> _t(Right(("a", 1)))(Either a (str, int))

21

Page 22: Мир Python  функционалим с помощью библиотек

А теперь к “болезни”

Ну наконец-то (с) Цитаты Великих Людей

иммутабельность, ленивостьалгебраические типы данных, pattern mathing

22

Page 23: Мир Python  функционалим с помощью библиотек

ЛенивостьОткладывать вычисление до тех пор, пока не понадобится результат

23

Page 24: Мир Python  функционалим с помощью библиотек

ЛенивостьОткладывать вычисление до тех пор, пока не понадобится результат

Для справки:В Python3 многие методы стали возвращать

итераторы, а не готовые данные

Память расходуется по необходимости (при запросе), что тоже можно назвать ленивым поведением

24

Page 25: Мир Python  функционалим с помощью библиотек

Ленивость на чистом Pythondef lazy_property(fn): """Decorator that makes a property lazy-evaluated.""" attr_name = '_lazy_' + fn.__name__

@property def _lazy_property(self): if not hasattr(self, attr_name): setattr(self, attr_name, fn(self)) return getattr(self, attr_name) return _lazy_property

class Person(object): def __init__(self, name, occupation): self.name = name self.occupation = occupation

@lazy_property def relatives(self): relatives = "Many relatives." return relatives

def main(): Jhon = Person('Jhon', 'Coder') print("Name: {0} Occupation: {1}".format(Jhon.name, Jhon.occupation)) print("Before we access `relatives`:") print(Jhon.__dict__) print("Jhon's relatives: {0}".format(Jhon.relatives)) print("After we've accessed `relatives`:") print(Jhon.__dict__)

main()

### OUTPUT #### Name: Jhon Occupation: Coder# Before we access `relatives`:# {'name': 'Jhon', 'occupation': 'Coder'}# Jhon's relatives: Many relatives.# After we've accessed `relatives`:# {'_lazy_relatives': 'Many relatives.', 'name': 'Jhon', 'occupation': 'Coder'}

25

Page 26: Мир Python  функционалим с помощью библиотек

Лень + funcy

Не поддерживает!

26

Page 27: Мир Python  функционалим с помощью библиотек

Лень + funcy

А точнее:использует итераторы из Python

27

Page 28: Мир Python  функционалим с помощью библиотек

Лень + fn.py

Ленивые Streams

28

Page 29: Мир Python  функционалим с помощью библиотек

Лень + fn.py

Ленивые StreamsПо сути это итераторы

29

Page 30: Мир Python  функционалим с помощью библиотек

Лень + fn.py

from fn import Stream

from fn.iters import take, drop, map

from operator import add

f = Stream()

fib = f << [0, 1] << map(add, f, drop(1, f))

assert list(take(10, fib)) == [0,1,1,2,3,5,8,13,21,34]

assert fib[20] == 6765

assert list(fib[30:35]) == [832040,1346269,2178309,3524578,5702887]

Ленивое вычисление чисел Фибоначчи

30

Page 31: Мир Python  функционалим с помощью библиотек

Лень + fn.py

class _StreamIterator(object): __slots__ = ("_stream", "_position")

def __init__(self, stream): self._stream = stream self._position = -1

def __next__(self): self._position += 1 if (len(self._stream._collection) > self._position or self._stream._fill_to(self._position)): return self._stream._collection[self._position]

raise StopIteration()

if version_info[0] == 2: next = __next__

Реализация Stream - https://github.com/kachayev/fn.py/blob/master/fn/stream.py

31

Page 32: Мир Python  функционалим с помощью библиотек

Лень + fn.py

class Stream(object): class _StreamIterator(object):

def __iter__(self): return self._StreamIterator(self) ...

Реализация Stream - https://github.com/kachayev/fn.py/blob/master/fn/stream.py

Stream возвращает значения в виде итераторов

А сам итератор возвращает настоящее значение

32

Page 33: Мир Python  функционалим с помощью библиотек

Лень + hask

Ленивые списки L[ ]>>> L[(x**2 for x in range(1, 11))]

L[1 ... ]

33

Page 34: Мир Python  функционалим с помощью библиотек

Лень + hask

Ленивые списки L[ ]Реализован примерно также, как и в fn.py

34

Page 35: Мир Python  функционалим с помощью библиотек

Лень + haskdef __getitem__(self, lst): if isinstance(lst, tuple) and len(lst) < 5 and \ any((Ellipsis is x for x in lst)): # L[x, ...] if len(lst) == 2 and lst[1] is Ellipsis: return enumFrom(lst[0]) # L[x, y, ...] elif len(lst) == 3 and lst[2] is Ellipsis: return enumFromThen(lst[0], lst[1]) # L[x, ..., y] elif len(lst) == 3 and lst[1] is Ellipsis: return enumFromTo(lst[0], lst[2]) # L[x, y, ..., z] elif len(lst) == 4 and lst[2] is Ellipsis: return enumFromThenTo(lst[0], lst[1], lst[3]) raise SyntaxError("Invalid list comprehension: %s" % str(lst)) elif hasattr(lst, "next") or hasattr(lst, "__next__"): return List(tail=lst) return List(head=lst)

Реализация синтаксиса“бесконечного” списка

35

Page 36: Мир Python  функционалим с помощью библиотек

Ленивая пауза

36

Page 37: Мир Python  функционалим с помощью библиотек

Pattern matchingCопоставление с образцом

?

37

Page 38: Мир Python  функционалим с помощью библиотек

Pattern matchingCопоставление с образцом

● Сравнение с точным значением

● Учет внутренней структуры объекта

● Сопоставление со строкой (regex)

38

Page 39: Мир Python  функционалим с помощью библиотек

PM + PEP 443>>> @fun.register(int)

... def _(arg, verbose=False):

... if verbose:

... print("Strength in numbers, eh?", end=" ")

... print(arg)

...

>>> @fun.register(list)

... def _(arg, verbose=False):

... if verbose:

... print("Enumerate this:")

... for i, elem in enumerate(arg):

... print(i, elem)

39

Page 40: Мир Python  функционалим с помощью библиотек

PM + patternsfrom patterns import patterns, Mismatch

@patterns

def factorial():

if 0: 1

if n is int: n * factorial(n-1)

if []: []

if [x] + xs: [factorial(x)] + factorial(xs)

if {'n': n, 'f': f}: f(factorial(n))

assert factorial(5) == 120

assert factorial([3,4,2]) == [6, 24, 2]

assert factorial({'n': [5, 1], 'f': sum}) == 121

factorial('hello') # raises Mismatch

Как работает?-

Парсит ASThttps://github.

com/Suor/patterns/blob/master/patterns/__init__.py

40

Page 41: Мир Python  функционалим с помощью библиотек

PM + haskdef fib(x):

return ~(caseof(x)

| m(0) >> 1

| m(1) >> 1

| m(m.n) >> fib(p.n - 1) + fib(p.n - 2))

>>> fib(1)

1

>>> fib(6)

13

Как работает?-

Организует свой стэк и анализирует frame

41

Page 42: Мир Python  функционалим с помощью библиотек

PM + haskdef pattern_match(value, pattern, env=None): """ Pattern match a value and a pattern. Args: value: the value to pattern-match on pattern: a pattern, consisting of literals and/or locally bound variables env: a dictionary of local variables bound while matching Returns: (True, env) if the match is successful, and (False, env) otherwise Raises: SyntaxError, if a variable name is used multiple times in the same pattern """ env = {} if env is None else env if isinstance(pattern, PatternMatchBind): if pattern.name in env: raise SyntaxError("Conflicting definitions for %s" % pattern.name) env[pattern.name] = value return True, env…. return False, env

42

Page 43: Мир Python  функционалим с помощью библиотек

PM + fn.py

Не поддерживает!

43

Page 44: Мир Python  функционалим с помощью библиотек

ИммутабельностьИммутабельность - это невозможность изменения состояния объекта с момента его создания.

“Строки is immutable”

(‘tuple is immutable’, )

44

Page 45: Мир Python  функционалим с помощью библиотек

Иммутабельность + fn.py

Множество готовых персистентных структур

LinkedList, Stack, Queue, Deque, ...

45

Page 46: Мир Python  функционалим с помощью библиотек

Иммутабельность + fn.py>>> from fn.immutable import SkewHeap

>>> s1 = SkewHeap(10)

>>> s2 = s1.insert(20)

>>> s2

<fn.immutable.heap.SkewHeap object at 0x10b14c050>

>>> s3 = s2.insert(30)

>>> s3

<fn.immutable.heap.SkewHeap object at 0x10b14c158> # <-- other object

>>> s3.extract()

(10, <fn.immutable.heap.SkewHeap object at 0x10b14c050>)

>>> s3.extract() # <-- s3 isn't changed

(10, <fn.immutable.heap.SkewHeap object at 0x10b11c052>)46

Page 47: Мир Python  функционалим с помощью библиотек

Иммутабельность + funcy

Не поддерживает!

47

Page 48: Мир Python  функционалим с помощью библиотек

Иммутабельность + hask

Иммутабельный список L[ ]

48

Page 49: Мир Python  функционалим с помощью библиотек

Иммутабельность + hask

def __add__(self, other): """ (+) :: [a] -> [a] -> [a] """ unify(self.__type__(), typeof(other)) if self.__is_evaluated and other.__is_evaluated: return List(head=self.__head + other.__head) elif self.__is_evaluated and not other.__is_evaluated: return List(head=self.__head + other.__head, tail=other.__tail) return List(head=self.__head, tail=itertools.chain(self.__tail, iter(other)))

Как работает?-

Персистентный список.

При добавлении элемента возвращает всегда новый список

49

Page 50: Мир Python  функционалим с помощью библиотек

Питоны кончились…НЕТ! Еще нет

50

Page 51: Мир Python  функционалим с помощью библиотек

Система типизации в hask

class Hask(object):

"""

Base class for objects within hask.

ADTs, TypedFunc, List, Undefined, and other hask-related types are all

subclasses of Hask.

All subclasses must define __type__, which returns a representation of the

object in the internal type system language.

"""

def __type__(self):

raise TypeError()

51

Page 52: Мир Python  функционалим с помощью библиотек

Система типизации в haskdef typeof(obj):

"""

Returns the type of an object within the internal type system.

Args:

obj: the object to inspect

Returns:

An object representing the type in the internal type system language

(i.e., a TypeOperator or TypeVariable)

"""

TypeVariable.next_var_name = 'a'

if isinstance(obj, Hask):

return obj.__type__()

elif isinstance(obj, tuple):

return Tuple(map(typeof, obj))

elif obj is None:

return TypeOperator(None, [])

elif type(obj) in __python_function_types__:

return TypeOperator(PyFunc, [])

return TypeOperator(type(obj), []) 52

Page 53: Мир Python  функционалим с помощью библиотек

53

[email protected]

@[email protected]

vk.com/pynsk

facebook.com/PyNskCom

PyNSK контакты: Мои контакты:

ru.linkedin.com/in/alexsapronov

Питоны кончились…Вопросы?

http://pynsk.ru