SlideShare a Scribd company logo
1 of 50
Download to read offline
Pyton – пробуем
функциональный
стиль
Жлобич Андрей
Wargaming.net
Python Developer
Minsk Python Meetup
Принципы ФП
✔ Чистота – нет побочных эффектов.
✔ Функции – сущности 1го рода.
✔ Функции высших порядков.
✔ Замыкания.
✔ Рекурсия.
✔ Неизменяемые структуры.
✔ Ленивые вычисления.
Versus
➔ Императивный стиль
➔ Функциональный Декларативный стиль
grep 'search-for' inputfile.txt > s1.txt
sort s1.txt > s2.txt
uniq s2.txt > result.txt
rm s1.txt s2.txt
cat inputfile.txt | grep 'search-for' |
sort | uniq | cat > result.txt
Чистые функции
def p_fact(n): # pure
return 1 if n < 2 else n * p_fact(n - 1)
def c_fact(n): # referentially transparent
try:
return c_fact._cache[n]
except KeyError:
x = c_fact._cache[n] = p_fact(n)
return x
c_fact._cache = {}
def o_fact(n): # io + logic - bad
f = p_fact(n)
print("{}! = {}".format(n, f)
return f
calculated_factorials = {}
def g_fact(n): # side effents
f = fact(n)
calculated_factorials[n] = f
return f
Побочные эффекты – плохо?
● Могут приводить к гейзенбагам.
● Без побочных эффектов никак не обойтись.
● Даже в pure-functional языках.
● Но их можно локализовать.
● Система типов может в этом помогать.
Ошибки начинающих
a = [[]] * 3
a[0].append(1)
print(a)
# [[1], [1], [1]] - WTF?
class Foo:
g = {}
def __init__(self, x):
self.g[x] = x
f1, f2 = Foo(5), Foo(6)
print(f2.x)
# {5:5, 6:6} - WTF
f = [lambda: i for i in [1, 2]]
for x in f:
print(x(), end="")
# 22 – WTF?
def f(x, a=[]):
a.append(x)
print(a)
print(f(1))
print(f(2))
# [1, 2] – WTF?
`
Мутабельный объект
class Point(object):
def __init__(self, x, y):
self.x, self.y = x, y
def move(self, dx, dy):
self.x += dx
self.y += dy
def distance(self, other):
return ((self.x - other.x) ** 2 +
(self.y - other.y) ** 2) ** 0.5
Немутабельный объект
class Point(object):
def __init__(self, x, y):
self.x, self.y = x, y
def move(self, dx, dy):
return Point(self.x + dx, self.y + dy)
def distance(self, other):
return ((self.x - other.x) ** 2 +
(self.y - other.y) ** 2) ** 0.5
А зачем тогда объект?
Point = namedtuple('Point', 'x, y')
def move_point(point, dx, dy):
return Point(point.x + dx, point.y + dy)
def distance(point1, point2):
return ((point1.x - point2.x) ** 2 +
(point1.y - point2.y) ** 2) ** 0.5
“Перестаньте писать классы”
class Greeting(object):
def __init__(self, word):
self.word = word
def greet(self, name):
return "{}, {}!".format(self.word, name)
greet_hello = Greeting('Hello').greet
# -- VERSUS --
def greet(word, name):
return "{}, {}!".format(word, name)
greet_hello = functools.partial(greet, 'Hello')
Высокоуровневые функции ввода-вывода
def process_line(line):
a, b = map(int, line.split())
return "out: " + str(a + b)
def interact(f):
for line in sys.stdin:
print(f(line))
def run():
interact(process_line)
Какой вариант лучше?
def print_result(val):
print("out:" + str(val))
def run():
for line in sys.stdin:
a, b = map(int, line.split())
print_result(a + b)
PEP 443 – singledispatch – in stdlib since 3.4
from singledispatch import singledispatch
@singledispatch
def move_point(point, x, y): ...
@move_point.register(tuple)
def _(point, x, y): ...
@move_point.register(Point)
def _(point, x, y): ...
Функции – сущности 1го рода
def singledispatch(func):
registry = {}
def dispatch(cls):
try:
return registry[cls]
except KeyError:
return _find_impl(cls, registry)
def register(cls, func=None):
if func is None:
return lambda f: register(cls, f)
registry[cls] = func
return func
def wrapper(*args, **kwargs):
return dispatch(args[0].__class__)(*args, **kwargs)
registry[object] = func
wrapper.register = register
wrapper.dispatch = dispatch
return wrapper
singledispatch – тест
CPython PyPy
0
10
20
30
40
50
60
70
80
90
class singledispatch
Origins of lambda
def genfunc(args, expr):
exec("def f(" + args + "): return " + expr)
return eval('f')
vals = [1, 2, 3]
newvals = map(genfunc('x', 'x * 2'), vals)
1993 – Python version < 1.0 – нет lambda
print map(lambda x: x * 2, [1, 2, 3])
# внутри другой функции - ERROR!
y = 2
print map(lambda x: x * y, [1, 2, 3])
# workaround
print map(lambda x, y=y: x * y, [1, 2, 3])
January 1994 – Python 1.0
Origins of lambda
Origins of lambda
April 2001 – Python 2.1 – замыкания
December 2008 – Python 3.0
● Больше итераторов (map, filter, dict values/keys).
● Хотели убрать lambda – оставили!
● Добавили nonlocal – мутабельные замыкания.
● Убрали reduce из builtins.
Sugared lambda
Добавляем “новый” синтаксис
from underscore import _
print map(_ + 1, [1, 2, 3])
assert (_)(1) == 1
assert (_ + _)(1, 2) == 3
assert ((_ * _) + _)(2, 3, 4) == 10
Sugared lambda – реализация
● Прототип underscore <90 строк.
● Реализации на pypi – fn, whatever.
● Нету замыканий, оверхед на создание.
class Underscore(object):
__slots__ = ['_arity', '_call']
def __init__(self, arity, call):
self._arity = arity
self._call = call
def __call__(self, *args):
return self._call(*args)
def __add__(self, value):
...
...
Sugared lambda – скорость
CPython PyPy
0
5
10
15
20
25
30
35
40
45
50
lambda underscore whatever fn
X 4
Функции высших порядков
Функции принимают другие функции в
качестве аргументов.
map, filter, timeit, iter...
Все декораторы!
trace, memoize, locking, transaction...
Пример
def process_file(filename):
with open(filename) as fp:
lines = iter(fp.readline, "")
ints = map(int, lines)
print map(memoize(func), ints)
timed(process_file)(filename)
Функции – тоже данные
● Можно хранить в структурах данных.
● Список или словарь функций – хорошо!
● Не забываем про замыкания.
● Функции – атомарные значения.
Функции везде
map("%s:%s".__mod__, zip("abc", [1, 2, 3]))
# ["a1", "b2", "c3"]
filter(set([1, 3]).__contains__, [2, 3, 4, 5])
# [3]
filter(bool, [1, 0, "", None, 3])
# [1, 3]
reduce(operator.mul, range(1, 5))
# 24
(F(f, a, b) << g << F(p, c))(x) ~~ f(a, b, g(p(c, x)))
from fn import F, _
F(add, 1)(10) # 11
f = F(add, 1) << F(mul, 100)
list(map(f, [0, 1, 2]))
# [1, 101, 201]
list(map(F() << str << (_ ** 2), range(1, 5)))
# ["1", "4", "9", "16"]
Readability counts
ss = ["list", "of", "words"]
# 1 – imperative
tlen = 0
for s in ss:
tlen += len(s)
# 2 – so ugly
reduce(lambda l,r: l+r, map(lambda s: len(s), ss))
# 3 – not bad
reduce(add, map(len, ss))
# 4 – good
sum(map(len, ss))
Рекурсия
● Во многих функциональных языках –
единственная операция для огранизации
цикла.
● Многие алгоритмы проще выражаются в
рамках рекурсии.
● Не типична для Python программ.
Хвостовая рекурсия
def factorial(n):
if n:
return n * factorial(n - 1)
else:
return 1
def factorial(n, acc=1):
if n:
return factorial(n – 1, n * acc)
else:
return acc
TCO в Python
● Мешает красивым стектрейсам.
● Это оптимизация – деталь реализации, а не
элемент языка.
● Рекурсия – не базовая операция в
программировании.
● Мешает динамичная сущность Python'а.
Trampoline
def trampoline(f):
def wrapper(*args, **kwargs):
ff = f(*args, **kwargs)
while callable(ff): ff = ff()
return ff
return wrapper
def factorial(n, acc=0):
if n:
return lambda: factorial(n - 1, n * acc)
else:
return acc
print(trampoline(factorial)(10))
Эмулируем
хвостовую рекурсию
Нельзя использовать
как декоратор!
Trampoline - варианты
def recur(*args, **kwargs): ...
@trampoline
def factorial(n, acc=0):
if n:
return recur(
n - 1, n * acc)
else:
return acc
@trampoline
def factorial(n, acc=0):
if n:
yield factorial(
n - 1, n * acc)
else:
return acc
Py3k only
Сами реализуем TCO
➔ Модификация байткода.
➔ Модификация исходного кода (препроцессинг).
➔ Анализ стека (sys._getframe()).
➔ Хранение локального состояния (threading.local).
Оптимизируем хвостовой вызов без
модификации самой функции
Используем threading.local
_FunCall = namedtuple(
'_FunCall', 'func, args, kwargs')
def tco(f):
tl = threading.local()
tl.trampolined = False
def func(*args, **kwargs):
if not tl.trampolined:
try:
tl.trampolined = True
while 1:
res = f(*args, **kwargs)
if isinstance(res, _FunCall) and 
res.func is f:
args = res.args
kwargs = res.kwargs
else:
return res
finally:
tl.trampolined = False
else:
return _FunCall(f, args, kwargs)
return func
Проще – быстрее?
Не обрабатывает
ситауцию
f → k → f
Используем sys._getframe()
TailRecurseCall = collections.namedtuple(
'TailRecurseCall', 'args, kwargs')
def tco(f):
def wrapper(*args, **kwargs):
fr = sys._getframe()
b = (fr.f_back and fr.f_back.f_back and
fr.f_back.f_back.f_code == fr.f_code)
del fr
if b:
return TailRecurseCall(args, kwargs)
else:
while 1:
r = f(*args, **kwargs)
if isinstance(r, TailRecurseCall):
args = r.args
kwargs = r.kwargs
else:
return r
return wrapper
trampoline на
стероидах
“правильная”
реализация
Trampoline/TCO bench
CPython PyPy
0
5
10
15
20
25
30
35
40
loop recursive trampoline tco-simple tco-getframe
X 5
Итераторы
● В Python они везде!
● Но в Python3K их еще больше.
● Простая универсальная абстракция.
● Ленивые вычисления.
● Простота композиции.
● Запись в “итеративном” стиле
(генераторы)
Itertools
things = [('2009-08-01', 11), ('2009-08-23', 3), ('2009-09-03', 10),
('2009-09-03', 4), ('2009-09-05', 22), ('2009-09-09', 33), ...]
get_date = itemgetter(0)
get_value = itemgetter(1)
filtered1 = dropwhile(lambda x: get_date(x) < '2009-09-01', things)
filtered2 = takewhile(lambda x: get_date(x) < '2009-10-01', things)
grouped_by_date = groupby(filtered2, get_date)
get_total_value = lambda (dt, items): 
(dt, reduce(add, map(get_value, items)))
result = sorted(map(get_total_value, grouped_by_date), key=get_value)
print(list(result))
# [('2009-09-03', 36), ('2009-09-06', 33)]
Funcy
from funcy import *
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')
some(even, [1, 2, 5]) # 2
take(4, iterate(double, 1)) # [1, 2, 4, 8]
first(drop(3, count(10))) # 13
split(odd, range(5)) # [[1, 3], [0, 2, 4]]
chunks(2, range(5)) # [[0, 1], [2, 3], [4]]
Итераторы не pure
odd = lambda x: bool(x % 2)
odds = ifilter(odd, count())
print(list(islice(odds, 4)))
# [1, 3, 5, 7] – ok
print(list(islice(odds, 4)))
# [9, 11, 13, 15] – WTF
Итераторы работают с побочными эффктами
Можно использовать (пройтись) только один раз.
Lazycol
class lazycol(object):
__slots__ = 'iterator'
def __new__(cls, iterable):
if isinstance(iterable, (tuple, frozenset, lazycol)):
return iterable
return object.__new__(cls)
def __init__(self, iterable):
self.iterator = iter(iterable)
def __iter__(self):
self.iterator, result = itertools.tee(self.iterator)
return result
Fn - Streams
s = Stream() << [1,2,3,4,5]
assert list(s) == [1,2,3,4,5]
assert s[1] == 2
assert 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]
● Элементы
вычисляются лениво
(“по требованию”).
● Элементы
кешируются.
● Коллекция, не
итератор.
● Мутабельная.
Fn - Streams
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 fib[20] == 6765
assert list(fib[30:34]) == [832040,1346269,2178309,3524578]
Ленивая бесконечная последовательность чисел фиббоначи
Иммутабельные структуры
● Нельзя случайно изменить – меньше
ошибок и времени в дебаггере.
● Могут быть оптимизированы для
многопоточных програм – не в Python.
● Могут разделять общую структуру.
● Встроенные: str, tuple, frozenset.
frozenlist, frozendict
def _build_fmethod(parent_method):
def method(self, *args, **kwargs):
if self._frozen: raise TypeError("frozen list")
return parent_method(self, *args, **kwargs)
return method
class frozenlist(list):
def __init__(self, iterable=None):
list.__init__(self, iterable)
self._frozen = False
if __debug__:
for mn in ['append', 'extend', …, '__delitem__']:
locals()[mn] = _build_fmethod(getattr(list, mn))
def freeze(self):
self._frozen = True
Иммутабельные структуры – реализации
● immutablepy
● dictproxyhack
● fronzendict
● changeless
● werkzeug.datastructures
● sqlalchemy.util
Персистентные структуры
● Хрянят “историю”
● Разделяют общую
структуру
● Используются в
Clojure, Git, CouchDB
Funktown
v = ImmutableVector([1, 2, 3])
v2 = v.conj(9)
print(v2)
# [1, 2, 3, 9]
v = v.assoc(1, 999)
print(v, v[1])
# 999
v = v.conj([])
v[3].append('BAD')
print(v)
# [1, 2, 3, ['BAD']]
d = ImmutableDict({'a': 1})
d = d.assoc('b', 2)
print(d['b'], d.get('b'))
# 2 2
print(d.assoc('c', 9))
# {'a': 1, 'c': 9, 'b': 2}
print(d.remove('d'))
# {'a': 1, 'b': 2}
print(d.items())
# [('a', 1), ('b', 2)]
I have never considered Python to be
heavily influenced by functional
languages, no matter what people say or
think. I was much more familiar with
imperative languages such as C and Algol
68 and although I had made functions
first-class objects, I didn't view Python as
a functional programming language.
Мнение автора языка
Guido van Rossum
В завершение
● Python – не функциональный язык.
● Но в нем есть функциональные элементы.
● Избегайте побочных эффектов.
● Не стоит увлекаться классами.
● Плохой код можно написать в любом стиле.
● В любом случае весьма полезно познакомится
с Clojure, Haskell, Erlang и другими.
Minsk Python Meetup
Всем большое
спасибо за внимание
вопросы?
a.zhlobich@gmail.com
anjensan@jabber.ru
anjensan at github, habrahabr etc

More Related Content

What's hot

Лекция 2. Всё, что вы хотели знать о функциях в Python.
Лекция 2. Всё, что вы хотели знать о функциях в Python.Лекция 2. Всё, что вы хотели знать о функциях в Python.
Лекция 2. Всё, что вы хотели знать о функциях в Python.Roman Brovko
 
Декораторы в Python и их практическое использование
Декораторы в Python и их практическое использование Декораторы в Python и их практическое использование
Декораторы в Python и их практическое использование Sergey Schetinin
 
Python и его тормоза
Python и его тормозаPython и его тормоза
Python и его тормозаAlexander Shigin
 
Магия в Python: Дескрипторы. Что это?
Магия в Python: Дескрипторы. Что это?Магия в Python: Дескрипторы. Что это?
Магия в Python: Дескрипторы. Что это?PyNSK
 
Лекция 4. Строки, байты, файлы и ввод/вывод.
 Лекция 4. Строки, байты, файлы и ввод/вывод. Лекция 4. Строки, байты, файлы и ввод/вывод.
Лекция 4. Строки, байты, файлы и ввод/вывод.Roman Brovko
 
Лекция 8. Итераторы, генераторы и модуль itertools.
 Лекция 8. Итераторы, генераторы и модуль itertools. Лекция 8. Итераторы, генераторы и модуль itertools.
Лекция 8. Итераторы, генераторы и модуль itertools.Roman Brovko
 
Лекция 12. Быстрее, Python, ещё быстрее.
Лекция 12. Быстрее, Python, ещё быстрее.Лекция 12. Быстрее, Python, ещё быстрее.
Лекция 12. Быстрее, Python, ещё быстрее.Roman Brovko
 
Лекция 10. Классы 2.
Лекция 10. Классы 2.Лекция 10. Классы 2.
Лекция 10. Классы 2.Roman Brovko
 
Лекция 9. Модули, пакеты и система импорта.
Лекция 9. Модули, пакеты и система импорта.Лекция 9. Модули, пакеты и система импорта.
Лекция 9. Модули, пакеты и система импорта.Roman Brovko
 
Python dict: прошлое, настоящее, будущее
Python dict: прошлое, настоящее, будущееPython dict: прошлое, настоящее, будущее
Python dict: прошлое, настоящее, будущееdelimitry
 
Python. Объектно-ориентированное программирование
Python. Объектно-ориентированное программирование Python. Объектно-ориентированное программирование
Python. Объектно-ориентированное программирование Theoretical mechanics department
 
Оптимизация производительности Python
Оптимизация производительности PythonОптимизация производительности Python
Оптимизация производительности PythonPyNSK
 
Производительность в Django
Производительность в DjangoПроизводительность в Django
Производительность в DjangoMoscowDjango
 
Лекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILЛекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILRoman Brovko
 
Лекция 5. Встроенные коллекции и модуль collections.
Лекция 5. Встроенные коллекции и модуль collections.Лекция 5. Встроенные коллекции и модуль collections.
Лекция 5. Встроенные коллекции и модуль collections.Roman Brovko
 
2.4 Использование указателей
2.4 Использование указателей2.4 Использование указателей
2.4 Использование указателейDEVTYPE
 

What's hot (20)

Лекция 2. Всё, что вы хотели знать о функциях в Python.
Лекция 2. Всё, что вы хотели знать о функциях в Python.Лекция 2. Всё, что вы хотели знать о функциях в Python.
Лекция 2. Всё, что вы хотели знать о функциях в Python.
 
Декораторы в Python и их практическое использование
Декораторы в Python и их практическое использование Декораторы в Python и их практическое использование
Декораторы в Python и их практическое использование
 
Python и его тормоза
Python и его тормозаPython и его тормоза
Python и его тормоза
 
Магия в Python: Дескрипторы. Что это?
Магия в Python: Дескрипторы. Что это?Магия в Python: Дескрипторы. Что это?
Магия в Python: Дескрипторы. Что это?
 
Лекция 4. Строки, байты, файлы и ввод/вывод.
 Лекция 4. Строки, байты, файлы и ввод/вывод. Лекция 4. Строки, байты, файлы и ввод/вывод.
Лекция 4. Строки, байты, файлы и ввод/вывод.
 
Лекция 8. Итераторы, генераторы и модуль itertools.
 Лекция 8. Итераторы, генераторы и модуль itertools. Лекция 8. Итераторы, генераторы и модуль itertools.
Лекция 8. Итераторы, генераторы и модуль itertools.
 
Лекция 12. Быстрее, Python, ещё быстрее.
Лекция 12. Быстрее, Python, ещё быстрее.Лекция 12. Быстрее, Python, ещё быстрее.
Лекция 12. Быстрее, Python, ещё быстрее.
 
Лекция 10. Классы 2.
Лекция 10. Классы 2.Лекция 10. Классы 2.
Лекция 10. Классы 2.
 
Лекция 9. Модули, пакеты и система импорта.
Лекция 9. Модули, пакеты и система импорта.Лекция 9. Модули, пакеты и система импорта.
Лекция 9. Модули, пакеты и система импорта.
 
Python dict: прошлое, настоящее, будущее
Python dict: прошлое, настоящее, будущееPython dict: прошлое, настоящее, будущее
Python dict: прошлое, настоящее, будущее
 
Scala #3
Scala #3Scala #3
Scala #3
 
Python. Объектно-ориентированное программирование
Python. Объектно-ориентированное программирование Python. Объектно-ориентированное программирование
Python. Объектно-ориентированное программирование
 
Оптимизация производительности Python
Оптимизация производительности PythonОптимизация производительности Python
Оптимизация производительности Python
 
Производительность в Django
Производительность в DjangoПроизводительность в Django
Производительность в Django
 
Лекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GILЛекция 13. Многопоточность и GIL
Лекция 13. Многопоточность и GIL
 
Лекция 5. Встроенные коллекции и модуль collections.
Лекция 5. Встроенные коллекции и модуль collections.Лекция 5. Встроенные коллекции и модуль collections.
Лекция 5. Встроенные коллекции и модуль collections.
 
Основы NumPy
Основы NumPyОсновы NumPy
Основы NumPy
 
2.4 Использование указателей
2.4 Использование указателей2.4 Использование указателей
2.4 Использование указателей
 
Основы Python. Функции
Основы Python. ФункцииОсновы Python. Функции
Основы Python. Функции
 
Основы SciPy
Основы SciPyОсновы SciPy
Основы SciPy
 

Similar to Pyton – пробуем функциональный стиль

Лекция о языке программирования Haskell
Лекция о языке программирования HaskellЛекция о языке программирования Haskell
Лекция о языке программирования Haskellhusniyarova
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовMikhail Kurnosov
 
Лекция 11: Методы разработки алгоритмов
Лекция 11: Методы разработки алгоритмовЛекция 11: Методы разработки алгоритмов
Лекция 11: Методы разработки алгоритмовMikhail Kurnosov
 
Функциональное программирование на F#
Функциональное программирование на F#Функциональное программирование на F#
Функциональное программирование на F#akrakovetsky
 
Лекция 13: Трудноразрешимые задачи. NP-полнота.
Лекция 13: Трудноразрешимые задачи. NP-полнота.Лекция 13: Трудноразрешимые задачи. NP-полнота.
Лекция 13: Трудноразрешимые задачи. NP-полнота.Mikhail Kurnosov
 
Николай Паламарчук "Functional Programming basics for PHP developers"
Николай Паламарчук "Functional Programming basics for PHP developers"Николай Паламарчук "Functional Programming basics for PHP developers"
Николай Паламарчук "Functional Programming basics for PHP developers"Fwdays
 
Использование GNU OCTAVE для инженерных и математических расчетов
Использование GNU OCTAVE для инженерных и математических расчетовИспользование GNU OCTAVE для инженерных и математических расчетов
Использование GNU OCTAVE для инженерных и математических расчетовТранслируем.бел
 
ITMO RecSys course. Autumn 2014. Lecture 3
ITMO RecSys course. Autumn 2014. Lecture 3ITMO RecSys course. Autumn 2014. Lecture 3
ITMO RecSys course. Autumn 2014. Lecture 3Andrey Danilchenko
 
Haskell Type System with Dzmitry Ivashnev.
Haskell Type System with Dzmitry Ivashnev.Haskell Type System with Dzmitry Ivashnev.
Haskell Type System with Dzmitry Ivashnev.Sergey Tihon
 
Tech Talks @NSU: Теоретические основы программирования: проекции Футамуры-Тур...
Tech Talks @NSU: Теоретические основы программирования: проекции Футамуры-Тур...Tech Talks @NSU: Теоретические основы программирования: проекции Футамуры-Тур...
Tech Talks @NSU: Теоретические основы программирования: проекции Футамуры-Тур...Tech Talks @NSU
 
Характерные черты функциональных языков программирования
Характерные черты функциональных языков программированияХарактерные черты функциональных языков программирования
Характерные черты функциональных языков программированияAlex.Kolonitsky
 
Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Яковенко Кирилл
 
Back to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодняBack to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодняAlexander Granin
 
Язык программирования Go для Perl-программистов
Язык программирования Go для Perl-программистовЯзык программирования Go для Perl-программистов
Язык программирования Go для Perl-программистовAndrew Shitov
 

Similar to Pyton – пробуем функциональный стиль (20)

Лекция о языке программирования Haskell
Лекция о языке программирования HaskellЛекция о языке программирования Haskell
Лекция о языке программирования Haskell
 
Лекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмовЛекция 11. Методы разработки алгоритмов
Лекция 11. Методы разработки алгоритмов
 
Лекция 11: Методы разработки алгоритмов
Лекция 11: Методы разработки алгоритмовЛекция 11: Методы разработки алгоритмов
Лекция 11: Методы разработки алгоритмов
 
Decorators' recipes
Decorators' recipesDecorators' recipes
Decorators' recipes
 
Функциональное программирование на F#
Функциональное программирование на F#Функциональное программирование на F#
Функциональное программирование на F#
 
Clojure #1
Clojure #1Clojure #1
Clojure #1
 
Лекция 13: Трудноразрешимые задачи. NP-полнота.
Лекция 13: Трудноразрешимые задачи. NP-полнота.Лекция 13: Трудноразрешимые задачи. NP-полнота.
Лекция 13: Трудноразрешимые задачи. NP-полнота.
 
Николай Паламарчук "Functional Programming basics for PHP developers"
Николай Паламарчук "Functional Programming basics for PHP developers"Николай Паламарчук "Functional Programming basics for PHP developers"
Николай Паламарчук "Functional Programming basics for PHP developers"
 
Использование GNU OCTAVE для инженерных и математических расчетов
Использование GNU OCTAVE для инженерных и математических расчетовИспользование GNU OCTAVE для инженерных и математических расчетов
Использование GNU OCTAVE для инженерных и математических расчетов
 
ITMO RecSys course. Autumn 2014. Lecture 3
ITMO RecSys course. Autumn 2014. Lecture 3ITMO RecSys course. Autumn 2014. Lecture 3
ITMO RecSys course. Autumn 2014. Lecture 3
 
Функциональное программирование.Списки. Функции высших порядков
Функциональное программирование.Списки. Функции высших порядковФункциональное программирование.Списки. Функции высших порядков
Функциональное программирование.Списки. Функции высших порядков
 
Урок 3. Карринг и ленивые вычисления.
Урок 3. Карринг и ленивые вычисления.Урок 3. Карринг и ленивые вычисления.
Урок 3. Карринг и ленивые вычисления.
 
Haskell Type System with Dzmitry Ivashnev.
Haskell Type System with Dzmitry Ivashnev.Haskell Type System with Dzmitry Ivashnev.
Haskell Type System with Dzmitry Ivashnev.
 
Tech Talks @NSU: Теоретические основы программирования: проекции Футамуры-Тур...
Tech Talks @NSU: Теоретические основы программирования: проекции Футамуры-Тур...Tech Talks @NSU: Теоретические основы программирования: проекции Футамуры-Тур...
Tech Talks @NSU: Теоретические основы программирования: проекции Футамуры-Тур...
 
Урок 8. Введение в редукцию графов
Урок 8. Введение в редукцию графовУрок 8. Введение в редукцию графов
Урок 8. Введение в редукцию графов
 
Характерные черты функциональных языков программирования
Характерные черты функциональных языков программированияХарактерные черты функциональных языков программирования
Характерные черты функциональных языков программирования
 
Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3Лекция #5. Введение в язык программирования Python 3
Лекция #5. Введение в язык программирования Python 3
 
Back to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодняBack to the future: Функциональное программирование вчера и сегодня
Back to the future: Функциональное программирование вчера и сегодня
 
Scala on android
Scala on androidScala on android
Scala on android
 
Язык программирования Go для Perl-программистов
Язык программирования Go для Perl-программистовЯзык программирования Go для Perl-программистов
Язык программирования Go для Perl-программистов
 

More from Python Meetup

Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15] Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15] Python Meetup
 
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...Python Meetup
 
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]Python Meetup
 
Practical Python Packaging / Стас Рудаков / Web Developer Wargaming
 Practical Python Packaging / Стас Рудаков / Web Developer Wargaming Practical Python Packaging / Стас Рудаков / Web Developer Wargaming
Practical Python Packaging / Стас Рудаков / Web Developer WargamingPython Meetup
 
Python&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython Meetup
 
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...Python Meetup
 
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...Python Meetup
 
Про асинхронность / Максим Щепелин / Web Developer Wargaming
Про асинхронность / Максим Щепелин / Web Developer WargamingПро асинхронность / Максим Щепелин / Web Developer Wargaming
Про асинхронность / Максим Щепелин / Web Developer WargamingPython Meetup
 
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014Python Meetup
 
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотекSWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотекPython Meetup
 
Wargaming: тыл - фронту!
Wargaming: тыл - фронту!Wargaming: тыл - фронту!
Wargaming: тыл - фронту!Python Meetup
 
Язык программирования GO
Язык программирования GOЯзык программирования GO
Язык программирования GOPython Meetup
 
Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Python Meetup
 
Redis. Как мы боролись со сложностью
Redis. Как мы боролись со сложностьюRedis. Как мы боролись со сложностью
Redis. Как мы боролись со сложностьюPython Meetup
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка TwistedPython Meetup
 
Обзор способов написания конкурентных программ в питоне
Обзор способов написания конкурентных программ в питоне Обзор способов написания конкурентных программ в питоне
Обзор способов написания конкурентных программ в питоне Python Meetup
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеPython Meetup
 
Python для анализа данных
Python для анализа данныхPython для анализа данных
Python для анализа данныхPython Meetup
 
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...Python Meetup
 

More from Python Meetup (20)

Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15] Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
 
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
 
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
Python AST / Николай Карелин / VPI Development Center [Python Meetup 27.03.15]
 
Practical Python Packaging / Стас Рудаков / Web Developer Wargaming
 Practical Python Packaging / Стас Рудаков / Web Developer Wargaming Practical Python Packaging / Стас Рудаков / Web Developer Wargaming
Practical Python Packaging / Стас Рудаков / Web Developer Wargaming
 
Python&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.by
 
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
 
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
 
Про асинхронность / Максим Щепелин / Web Developer Wargaming
Про асинхронность / Максим Щепелин / Web Developer WargamingПро асинхронность / Максим Щепелин / Web Developer Wargaming
Про асинхронность / Максим Щепелин / Web Developer Wargaming
 
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
 
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотекSWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
 
Wargaming: тыл - фронту!
Wargaming: тыл - фронту!Wargaming: тыл - фронту!
Wargaming: тыл - фронту!
 
Язык программирования GO
Язык программирования GOЯзык программирования GO
Язык программирования GO
 
Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"
 
Redis. Как мы боролись со сложностью
Redis. Как мы боролись со сложностьюRedis. Как мы боролись со сложностью
Redis. Как мы боролись со сложностью
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка Twisted
 
Обзор способов написания конкурентных программ в питоне
Обзор способов написания конкурентных программ в питоне Обзор способов написания конкурентных программ в питоне
Обзор способов написания конкурентных программ в питоне
 
Pebble
PebblePebble
Pebble
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгирование
 
Python для анализа данных
Python для анализа данныхPython для анализа данных
Python для анализа данных
 
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
 

Pyton – пробуем функциональный стиль

  • 1. Pyton – пробуем функциональный стиль Жлобич Андрей Wargaming.net Python Developer Minsk Python Meetup
  • 2. Принципы ФП ✔ Чистота – нет побочных эффектов. ✔ Функции – сущности 1го рода. ✔ Функции высших порядков. ✔ Замыкания. ✔ Рекурсия. ✔ Неизменяемые структуры. ✔ Ленивые вычисления.
  • 3. Versus ➔ Императивный стиль ➔ Функциональный Декларативный стиль grep 'search-for' inputfile.txt > s1.txt sort s1.txt > s2.txt uniq s2.txt > result.txt rm s1.txt s2.txt cat inputfile.txt | grep 'search-for' | sort | uniq | cat > result.txt
  • 4. Чистые функции def p_fact(n): # pure return 1 if n < 2 else n * p_fact(n - 1) def c_fact(n): # referentially transparent try: return c_fact._cache[n] except KeyError: x = c_fact._cache[n] = p_fact(n) return x c_fact._cache = {} def o_fact(n): # io + logic - bad f = p_fact(n) print("{}! = {}".format(n, f) return f calculated_factorials = {} def g_fact(n): # side effents f = fact(n) calculated_factorials[n] = f return f
  • 5. Побочные эффекты – плохо? ● Могут приводить к гейзенбагам. ● Без побочных эффектов никак не обойтись. ● Даже в pure-functional языках. ● Но их можно локализовать. ● Система типов может в этом помогать.
  • 6. Ошибки начинающих a = [[]] * 3 a[0].append(1) print(a) # [[1], [1], [1]] - WTF? class Foo: g = {} def __init__(self, x): self.g[x] = x f1, f2 = Foo(5), Foo(6) print(f2.x) # {5:5, 6:6} - WTF f = [lambda: i for i in [1, 2]] for x in f: print(x(), end="") # 22 – WTF? def f(x, a=[]): a.append(x) print(a) print(f(1)) print(f(2)) # [1, 2] – WTF? `
  • 7. Мутабельный объект class Point(object): def __init__(self, x, y): self.x, self.y = x, y def move(self, dx, dy): self.x += dx self.y += dy def distance(self, other): return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5
  • 8. Немутабельный объект class Point(object): def __init__(self, x, y): self.x, self.y = x, y def move(self, dx, dy): return Point(self.x + dx, self.y + dy) def distance(self, other): return ((self.x - other.x) ** 2 + (self.y - other.y) ** 2) ** 0.5
  • 9. А зачем тогда объект? Point = namedtuple('Point', 'x, y') def move_point(point, dx, dy): return Point(point.x + dx, point.y + dy) def distance(point1, point2): return ((point1.x - point2.x) ** 2 + (point1.y - point2.y) ** 2) ** 0.5
  • 10. “Перестаньте писать классы” class Greeting(object): def __init__(self, word): self.word = word def greet(self, name): return "{}, {}!".format(self.word, name) greet_hello = Greeting('Hello').greet # -- VERSUS -- def greet(word, name): return "{}, {}!".format(word, name) greet_hello = functools.partial(greet, 'Hello')
  • 11. Высокоуровневые функции ввода-вывода def process_line(line): a, b = map(int, line.split()) return "out: " + str(a + b) def interact(f): for line in sys.stdin: print(f(line)) def run(): interact(process_line) Какой вариант лучше? def print_result(val): print("out:" + str(val)) def run(): for line in sys.stdin: a, b = map(int, line.split()) print_result(a + b)
  • 12. PEP 443 – singledispatch – in stdlib since 3.4 from singledispatch import singledispatch @singledispatch def move_point(point, x, y): ... @move_point.register(tuple) def _(point, x, y): ... @move_point.register(Point) def _(point, x, y): ...
  • 13. Функции – сущности 1го рода def singledispatch(func): registry = {} def dispatch(cls): try: return registry[cls] except KeyError: return _find_impl(cls, registry) def register(cls, func=None): if func is None: return lambda f: register(cls, f) registry[cls] = func return func def wrapper(*args, **kwargs): return dispatch(args[0].__class__)(*args, **kwargs) registry[object] = func wrapper.register = register wrapper.dispatch = dispatch return wrapper
  • 14. singledispatch – тест CPython PyPy 0 10 20 30 40 50 60 70 80 90 class singledispatch
  • 15. Origins of lambda def genfunc(args, expr): exec("def f(" + args + "): return " + expr) return eval('f') vals = [1, 2, 3] newvals = map(genfunc('x', 'x * 2'), vals) 1993 – Python version < 1.0 – нет lambda
  • 16. print map(lambda x: x * 2, [1, 2, 3]) # внутри другой функции - ERROR! y = 2 print map(lambda x: x * y, [1, 2, 3]) # workaround print map(lambda x, y=y: x * y, [1, 2, 3]) January 1994 – Python 1.0 Origins of lambda
  • 17. Origins of lambda April 2001 – Python 2.1 – замыкания December 2008 – Python 3.0 ● Больше итераторов (map, filter, dict values/keys). ● Хотели убрать lambda – оставили! ● Добавили nonlocal – мутабельные замыкания. ● Убрали reduce из builtins.
  • 18. Sugared lambda Добавляем “новый” синтаксис from underscore import _ print map(_ + 1, [1, 2, 3]) assert (_)(1) == 1 assert (_ + _)(1, 2) == 3 assert ((_ * _) + _)(2, 3, 4) == 10
  • 19. Sugared lambda – реализация ● Прототип underscore <90 строк. ● Реализации на pypi – fn, whatever. ● Нету замыканий, оверхед на создание. class Underscore(object): __slots__ = ['_arity', '_call'] def __init__(self, arity, call): self._arity = arity self._call = call def __call__(self, *args): return self._call(*args) def __add__(self, value): ... ...
  • 20. Sugared lambda – скорость CPython PyPy 0 5 10 15 20 25 30 35 40 45 50 lambda underscore whatever fn X 4
  • 21. Функции высших порядков Функции принимают другие функции в качестве аргументов. map, filter, timeit, iter... Все декораторы! trace, memoize, locking, transaction...
  • 22. Пример def process_file(filename): with open(filename) as fp: lines = iter(fp.readline, "") ints = map(int, lines) print map(memoize(func), ints) timed(process_file)(filename)
  • 23. Функции – тоже данные ● Можно хранить в структурах данных. ● Список или словарь функций – хорошо! ● Не забываем про замыкания. ● Функции – атомарные значения.
  • 24. Функции везде map("%s:%s".__mod__, zip("abc", [1, 2, 3])) # ["a1", "b2", "c3"] filter(set([1, 3]).__contains__, [2, 3, 4, 5]) # [3] filter(bool, [1, 0, "", None, 3]) # [1, 3] reduce(operator.mul, range(1, 5)) # 24
  • 25. (F(f, a, b) << g << F(p, c))(x) ~~ f(a, b, g(p(c, x))) from fn import F, _ F(add, 1)(10) # 11 f = F(add, 1) << F(mul, 100) list(map(f, [0, 1, 2])) # [1, 101, 201] list(map(F() << str << (_ ** 2), range(1, 5))) # ["1", "4", "9", "16"]
  • 26. Readability counts ss = ["list", "of", "words"] # 1 – imperative tlen = 0 for s in ss: tlen += len(s) # 2 – so ugly reduce(lambda l,r: l+r, map(lambda s: len(s), ss)) # 3 – not bad reduce(add, map(len, ss)) # 4 – good sum(map(len, ss))
  • 27. Рекурсия ● Во многих функциональных языках – единственная операция для огранизации цикла. ● Многие алгоритмы проще выражаются в рамках рекурсии. ● Не типична для Python программ.
  • 28. Хвостовая рекурсия def factorial(n): if n: return n * factorial(n - 1) else: return 1 def factorial(n, acc=1): if n: return factorial(n – 1, n * acc) else: return acc
  • 29. TCO в Python ● Мешает красивым стектрейсам. ● Это оптимизация – деталь реализации, а не элемент языка. ● Рекурсия – не базовая операция в программировании. ● Мешает динамичная сущность Python'а.
  • 30. Trampoline def trampoline(f): def wrapper(*args, **kwargs): ff = f(*args, **kwargs) while callable(ff): ff = ff() return ff return wrapper def factorial(n, acc=0): if n: return lambda: factorial(n - 1, n * acc) else: return acc print(trampoline(factorial)(10)) Эмулируем хвостовую рекурсию Нельзя использовать как декоратор!
  • 31. Trampoline - варианты def recur(*args, **kwargs): ... @trampoline def factorial(n, acc=0): if n: return recur( n - 1, n * acc) else: return acc @trampoline def factorial(n, acc=0): if n: yield factorial( n - 1, n * acc) else: return acc Py3k only
  • 32. Сами реализуем TCO ➔ Модификация байткода. ➔ Модификация исходного кода (препроцессинг). ➔ Анализ стека (sys._getframe()). ➔ Хранение локального состояния (threading.local). Оптимизируем хвостовой вызов без модификации самой функции
  • 33. Используем threading.local _FunCall = namedtuple( '_FunCall', 'func, args, kwargs') def tco(f): tl = threading.local() tl.trampolined = False def func(*args, **kwargs): if not tl.trampolined: try: tl.trampolined = True while 1: res = f(*args, **kwargs) if isinstance(res, _FunCall) and res.func is f: args = res.args kwargs = res.kwargs else: return res finally: tl.trampolined = False else: return _FunCall(f, args, kwargs) return func Проще – быстрее? Не обрабатывает ситауцию f → k → f
  • 34. Используем sys._getframe() TailRecurseCall = collections.namedtuple( 'TailRecurseCall', 'args, kwargs') def tco(f): def wrapper(*args, **kwargs): fr = sys._getframe() b = (fr.f_back and fr.f_back.f_back and fr.f_back.f_back.f_code == fr.f_code) del fr if b: return TailRecurseCall(args, kwargs) else: while 1: r = f(*args, **kwargs) if isinstance(r, TailRecurseCall): args = r.args kwargs = r.kwargs else: return r return wrapper trampoline на стероидах “правильная” реализация
  • 35. Trampoline/TCO bench CPython PyPy 0 5 10 15 20 25 30 35 40 loop recursive trampoline tco-simple tco-getframe X 5
  • 36. Итераторы ● В Python они везде! ● Но в Python3K их еще больше. ● Простая универсальная абстракция. ● Ленивые вычисления. ● Простота композиции. ● Запись в “итеративном” стиле (генераторы)
  • 37. Itertools things = [('2009-08-01', 11), ('2009-08-23', 3), ('2009-09-03', 10), ('2009-09-03', 4), ('2009-09-05', 22), ('2009-09-09', 33), ...] get_date = itemgetter(0) get_value = itemgetter(1) filtered1 = dropwhile(lambda x: get_date(x) < '2009-09-01', things) filtered2 = takewhile(lambda x: get_date(x) < '2009-10-01', things) grouped_by_date = groupby(filtered2, get_date) get_total_value = lambda (dt, items): (dt, reduce(add, map(get_value, items))) result = sorted(map(get_total_value, grouped_by_date), key=get_value) print(list(result)) # [('2009-09-03', 36), ('2009-09-06', 33)]
  • 38. Funcy from funcy import * 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') some(even, [1, 2, 5]) # 2 take(4, iterate(double, 1)) # [1, 2, 4, 8] first(drop(3, count(10))) # 13 split(odd, range(5)) # [[1, 3], [0, 2, 4]] chunks(2, range(5)) # [[0, 1], [2, 3], [4]]
  • 39. Итераторы не pure odd = lambda x: bool(x % 2) odds = ifilter(odd, count()) print(list(islice(odds, 4))) # [1, 3, 5, 7] – ok print(list(islice(odds, 4))) # [9, 11, 13, 15] – WTF Итераторы работают с побочными эффктами Можно использовать (пройтись) только один раз.
  • 40. Lazycol class lazycol(object): __slots__ = 'iterator' def __new__(cls, iterable): if isinstance(iterable, (tuple, frozenset, lazycol)): return iterable return object.__new__(cls) def __init__(self, iterable): self.iterator = iter(iterable) def __iter__(self): self.iterator, result = itertools.tee(self.iterator) return result
  • 41. Fn - Streams s = Stream() << [1,2,3,4,5] assert list(s) == [1,2,3,4,5] assert s[1] == 2 assert 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] ● Элементы вычисляются лениво (“по требованию”). ● Элементы кешируются. ● Коллекция, не итератор. ● Мутабельная.
  • 42. Fn - Streams 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 fib[20] == 6765 assert list(fib[30:34]) == [832040,1346269,2178309,3524578] Ленивая бесконечная последовательность чисел фиббоначи
  • 43. Иммутабельные структуры ● Нельзя случайно изменить – меньше ошибок и времени в дебаггере. ● Могут быть оптимизированы для многопоточных програм – не в Python. ● Могут разделять общую структуру. ● Встроенные: str, tuple, frozenset.
  • 44. frozenlist, frozendict def _build_fmethod(parent_method): def method(self, *args, **kwargs): if self._frozen: raise TypeError("frozen list") return parent_method(self, *args, **kwargs) return method class frozenlist(list): def __init__(self, iterable=None): list.__init__(self, iterable) self._frozen = False if __debug__: for mn in ['append', 'extend', …, '__delitem__']: locals()[mn] = _build_fmethod(getattr(list, mn)) def freeze(self): self._frozen = True
  • 45. Иммутабельные структуры – реализации ● immutablepy ● dictproxyhack ● fronzendict ● changeless ● werkzeug.datastructures ● sqlalchemy.util
  • 46. Персистентные структуры ● Хрянят “историю” ● Разделяют общую структуру ● Используются в Clojure, Git, CouchDB
  • 47. Funktown v = ImmutableVector([1, 2, 3]) v2 = v.conj(9) print(v2) # [1, 2, 3, 9] v = v.assoc(1, 999) print(v, v[1]) # 999 v = v.conj([]) v[3].append('BAD') print(v) # [1, 2, 3, ['BAD']] d = ImmutableDict({'a': 1}) d = d.assoc('b', 2) print(d['b'], d.get('b')) # 2 2 print(d.assoc('c', 9)) # {'a': 1, 'c': 9, 'b': 2} print(d.remove('d')) # {'a': 1, 'b': 2} print(d.items()) # [('a', 1), ('b', 2)]
  • 48. I have never considered Python to be heavily influenced by functional languages, no matter what people say or think. I was much more familiar with imperative languages such as C and Algol 68 and although I had made functions first-class objects, I didn't view Python as a functional programming language. Мнение автора языка Guido van Rossum
  • 49. В завершение ● Python – не функциональный язык. ● Но в нем есть функциональные элементы. ● Избегайте побочных эффектов. ● Не стоит увлекаться классами. ● Плохой код можно написать в любом стиле. ● В любом случае весьма полезно познакомится с Clojure, Haskell, Erlang и другими.
  • 50. Minsk Python Meetup Всем большое спасибо за внимание вопросы? a.zhlobich@gmail.com anjensan@jabber.ru anjensan at github, habrahabr etc