Недостатки Python

Preview:

DESCRIPTION

В докладе раскрыты слабые места Python, проблемы с GC, функциональным стилем, реализацией стандартных структур данных и интерпретатора CPython. Автор: Кирилл Лашкевич

Citation preview

Python imperfectionsCyril @notorca Lashkevich

Элементы функционального стиля

Python не функциональный язык

Но иногда хочется…

… или случайно получается

Разминка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)

>> 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)

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

Захват переменных в замыкания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()

Захват переменных в замыкания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 beforeassignment

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

Генераторы и yield

Возможность удобно использовать генераторы в генераторах появилась только в 3.3, PEP 380 yield form

Даже с этим генераторы слабее более общей концепции coroutines

yield не функция, а синтаксический элемент привязанный к контексту, не first-class citizen

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)

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]

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)

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)

Неоднородность Object Model

weakref

__slots__

__del__

new/old style objects

Bytecode

PyObject * PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) { // ~2200 lines }

~110 инструкции байткода (39 в Lua)

void luaV_execute (lua_State *L) { // 320 lines }

API

Объемный и сложный в использовании

818 функции (3.3) vs 123 + 66 aux в Lua

Не все гладко с Py_Initialize/Py_Finalize

GIL

Глобальный для процесса семафор/conditional variable

Не дает нескольким потокам выполнятся одновременно…

…почти

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

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

GIL глобальный для процесса

The EndCyril @notorca Lashkevich

Recommended