Slide 1

Slide 1 text

Python imperfections Cyril @notorca Lashkevich

Slide 2

Slide 2 text

Элементы функционального стиля Python не функциональный язык Но иногда хочется… … или случайно получается

Slide 3

Slide 3 text

Разминка def empty(_): return None
 def add(d, k, v):
 def new_dict(x):
 if x == k:
 return v
 else:
 return d(x)
 return new_dict
 def add_f(d, k, v):
 return lambda x: v if k == x else d(x)

Slide 4

Slide 4 text

>> d = add(empty, 1, "abc") >> d = add_f(d, 2, "def") >> d(1) 'abc' >> d(2) 'def' >> d(0) >> Разминка def empty(_): return None
 def add(d, k, v):
 def new_dict(x):
 if x == k:
 return v
 else:
 return d(x)
 return new_dict
 def add_f(d, k, v):
 return lambda x: v if k == x else d(x)

Slide 5

Slide 5 text

Захват переменных в замыкания def Counter(x): a = x def zero(): a = 0 def val(): return a def inc(): a += 1 return a return (zero, val, inc)

Slide 6

Slide 6 text

Захват переменных в замыкания def Counter(x): a = x def zero(): a = 0 def val(): return a def inc(): a += 1 return a return (zero, val, inc) >> zero, val, inc = Counter(5) >> zero() >> val() 5 >> inc()

Slide 7

Slide 7 text

Захват переменных в замыкания def Counter(x): a = x def zero(): a = 0 def val(): return a def inc(): a += 1 return a return (zero, val, inc) >> zero, val, inc = Counter(5) >> zero() >> val() 5 >> inc() UnboundLocalError:
 local variable 'a'
 referenced before
 assignment

Slide 8

Slide 8 text

def Counter(x): a = x def zero(): nonlocal a = 0 def val(): return a def inc(): nonlocal a a += 1 return a return (zero, val, inc) def Counter(x): a = [x] def zero(): a[0] = 0 def val(): return a[0] def inc(): a[0] += 1 return a[0] return (zero, val, inc) 3.x 2.x

Slide 9

Slide 9 text

Генераторы и yield Возможность удобно использовать генераторы в генераторах появилась только в 3.3, PEP 380 yield form Даже с этим генераторы слабее более общей концепции coroutines yield не функция, а синтаксический элемент привязанный к контексту, не first-class citizen

Slide 10

Slide 10 text

def accumulate():
 res = 0
 while 1:
 n = yield
 if n is None:
 return res
 res += n
 def gather_sums(sums):
 while 1:
 s = yield from accumulate()
 sums.append(s)

Slide 11

Slide 11 text

def accumulate():
 res = 0
 while 1:
 n = yield
 if n is None:
 return res
 res += n
 def gather_sums(sums):
 while 1:
 s = yield from accumulate()
 sums.append(s) >> sums = [] >> acc = gather_sums(sums) >> next(acc) >> for i in range(4): .. acc.send(i) .. >> acc.send(None) >> for i in range(5): .. acc.send(i) .. >> acc.send(None) >> sums [6, 10]

Slide 12

Slide 12 text

def inorder(t):
 if t:
 for x in inorder(t.left):
 yield x
 yield t.label
 for x in inorder(t.right):
 yield x
 def inorder_33(t):
 if t:
 yield from inorder(t.left)
 yield t.label
 yield from inorder(t.right)

Slide 13

Slide 13 text

function inorder(f, t)
 if t then
 inorder(f, t.left)
 f(t.label)
 return inorder(f, t.right)
 end
 end
 for label in coroutine.wrap(inorder),
 coroutine.yield, t do
 -- something with label
 end
 inorder(print, t)

Slide 14

Slide 14 text

Неоднородность Object Model weakref __slots__ __del__ new/old style objects

Slide 15

Slide 15 text

Bytecode PyObject * PyEval_EvalFrameEx(PyFrameObject *f,
 int throwflag) { // ~2200 lines } ~110 инструкции байткода (39 в Lua) void luaV_execute (lua_State *L) { // 320 lines }

Slide 16

Slide 16 text

API Объемный и сложный в использовании 818 функции (3.3) vs 123 + 66 aux в Lua Не все гладко с Py_Initialize/Py_Finalize

Slide 17

Slide 17 text

GIL Глобальный для процесса семафор/ conditional variable Не дает нескольким потокам выполнятся одновременно… …почти

Slide 18

Slide 18 text

Программа на С создает потоки, в каждом из которых свой экземпляр интерпретатора?

Slide 19

Slide 19 text

Программа на С создает потоки, в каждом из которых свой экземпляр интерпретатора? GIL глобальный для процесса

Slide 20

Slide 20 text

The End Cyril @notorca Lashkevich