"Внутренности" cpython, часть ii

108
“Внутренности” CPython, часть вторая Никита Лесников

Upload: python-meetup

Post on 25-Dec-2014

976 views

Category:

Technology


2 download

DESCRIPTION

"Внутренности" CPython, часть II Автор: Никита Лесников (Wargaming)

TRANSCRIPT

Page 1: "Внутренности" CPython, часть II

“Внутренности” CPython, часть втораяНикита Лесников

Page 2: "Внутренности" CPython, часть II

Вспомнить все.

“Внутренности” CPython, часть вторая 2

Page 3: "Внутренности" CPython, часть II

Вспомнить все

Наверняка не все присутствовали на первой части моеговыступления

Это ведь было аж в июнеПоэтому кратко повторю, о чем мы собираемся разговаривать

“Внутренности” CPython, часть вторая 3

Page 4: "Внутренности" CPython, часть II

Вспомнить все

Наверняка не все присутствовали на первой части моеговыступленияЭто ведь было аж в июне

Поэтому кратко повторю, о чем мы собираемся разговаривать

“Внутренности” CPython, часть вторая 3

Page 5: "Внутренности" CPython, часть II

Вспомнить все

Наверняка не все присутствовали на первой части моеговыступленияЭто ведь было аж в июнеПоэтому кратко повторю, о чем мы собираемся разговаривать

“Внутренности” CPython, часть вторая 3

Page 6: "Внутренности" CPython, часть II

CPython

Основная реализация на сегодняшний день

Написана на C“Чистый” интерпретатор байткода, без JIT и AOT“Своя” VM, никаких отсылок к Java и .NET

“Внутренности” CPython, часть вторая 4

Page 7: "Внутренности" CPython, часть II

CPython

Основная реализация на сегодняшний деньНаписана на C

“Чистый” интерпретатор байткода, без JIT и AOT“Своя” VM, никаких отсылок к Java и .NET

“Внутренности” CPython, часть вторая 4

Page 8: "Внутренности" CPython, часть II

CPython

Основная реализация на сегодняшний деньНаписана на C“Чистый” интерпретатор байткода, без JIT и AOT

“Своя” VM, никаких отсылок к Java и .NET

“Внутренности” CPython, часть вторая 4

Page 9: "Внутренности" CPython, часть II

CPython

Основная реализация на сегодняшний деньНаписана на C“Чистый” интерпретатор байткода, без JIT и AOT“Своя” VM, никаких отсылок к Java и .NET

“Внутренности” CPython, часть вторая 4

Page 10: "Внутренности" CPython, часть II

Альтернативы

native+ - PyPy

.NET - IronPython, Boo (правда, строго говоря это не Python)JVM - JythonВозможно другие. Они нас сегодня не интересуют.Мы рассматриваем внутреннее устройство CPython.

“Внутренности” CPython, часть вторая 5

Page 11: "Внутренности" CPython, часть II

Альтернативы

native+ - PyPy.NET - IronPython, Boo (правда, строго говоря это не Python)

JVM - JythonВозможно другие. Они нас сегодня не интересуют.Мы рассматриваем внутреннее устройство CPython.

“Внутренности” CPython, часть вторая 5

Page 12: "Внутренности" CPython, часть II

Альтернативы

native+ - PyPy.NET - IronPython, Boo (правда, строго говоря это не Python)JVM - Jython

Возможно другие. Они нас сегодня не интересуют.Мы рассматриваем внутреннее устройство CPython.

“Внутренности” CPython, часть вторая 5

Page 13: "Внутренности" CPython, часть II

Альтернативы

native+ - PyPy.NET - IronPython, Boo (правда, строго говоря это не Python)JVM - JythonВозможно другие. Они нас сегодня не интересуют.

Мы рассматриваем внутреннее устройство CPython.

“Внутренности” CPython, часть вторая 5

Page 14: "Внутренности" CPython, часть II

Альтернативы

native+ - PyPy.NET - IronPython, Boo (правда, строго говоря это не Python)JVM - JythonВозможно другие. Они нас сегодня не интересуют.Мы рассматриваем внутреннее устройство CPython.

“Внутренности” CPython, часть вторая 5

Page 15: "Внутренности" CPython, часть II

Все - объект

В CPython все является объектом

Конкретнее - PyObject*Числа, строки, код, фреймы, модули - абсолютно всеЛюбой PyObject начинается одинаково:

#define PyObject_HEAD \Py_ssize_t ob_refcnt; \struct _typeobject *ob_type;

“Внутренности” CPython, часть вторая 6

Page 16: "Внутренности" CPython, часть II

Все - объект

В CPython все является объектомКонкретнее - PyObject*

Числа, строки, код, фреймы, модули - абсолютно всеЛюбой PyObject начинается одинаково:

#define PyObject_HEAD \Py_ssize_t ob_refcnt; \struct _typeobject *ob_type;

“Внутренности” CPython, часть вторая 6

Page 17: "Внутренности" CPython, часть II

Все - объект

В CPython все является объектомКонкретнее - PyObject*Числа, строки, код, фреймы, модули - абсолютно все

Любой PyObject начинается одинаково:

#define PyObject_HEAD \Py_ssize_t ob_refcnt; \struct _typeobject *ob_type;

“Внутренности” CPython, часть вторая 6

Page 18: "Внутренности" CPython, часть II

Все - объект

В CPython все является объектомКонкретнее - PyObject*Числа, строки, код, фреймы, модули - абсолютно всеЛюбой PyObject начинается одинаково:

#define PyObject_HEAD \Py_ssize_t ob_refcnt; \struct _typeobject *ob_type;

“Внутренности” CPython, часть вторая 6

Page 19: "Внутренности" CPython, часть II

PyObject

#define PyObject_HEAD \Py_ssize_t ob_refcnt; \struct _typeobject *ob_type;

ob_refcnt - reference count для управления памятью

ob_type - type object, задающий поведение конкретного объектаТо, что дальше, может быть чем угодно.

“Внутренности” CPython, часть вторая 7

Page 20: "Внутренности" CPython, часть II

PyObject

#define PyObject_HEAD \Py_ssize_t ob_refcnt; \struct _typeobject *ob_type;

ob_refcnt - reference count для управления памятьюob_type - type object, задающий поведение конкретного объекта

То, что дальше, может быть чем угодно.

“Внутренности” CPython, часть вторая 7

Page 21: "Внутренности" CPython, часть II

PyObject

#define PyObject_HEAD \Py_ssize_t ob_refcnt; \struct _typeobject *ob_type;

ob_refcnt - reference count для управления памятьюob_type - type object, задающий поведение конкретного объектаТо, что дальше, может быть чем угодно.

“Внутренности” CPython, часть вторая 7

Page 22: "Внутренности" CPython, часть II

code object

Код в Python - тоже объект.

Интерпретатор оперирует байткодом стековой машины.Инструкции занимают 1 байт, опционально принимают одиндвухбайтный аргумент.Константы сложных типов хранятся “рядом” в code object,обращение к ним происходит по индексу.

“Внутренности” CPython, часть вторая 8

Page 23: "Внутренности" CPython, часть II

code object

Код в Python - тоже объект.Интерпретатор оперирует байткодом стековой машины.

Инструкции занимают 1 байт, опционально принимают одиндвухбайтный аргумент.Константы сложных типов хранятся “рядом” в code object,обращение к ним происходит по индексу.

“Внутренности” CPython, часть вторая 8

Page 24: "Внутренности" CPython, часть II

code object

Код в Python - тоже объект.Интерпретатор оперирует байткодом стековой машины.Инструкции занимают 1 байт, опционально принимают одиндвухбайтный аргумент.

Константы сложных типов хранятся “рядом” в code object,обращение к ним происходит по индексу.

“Внутренности” CPython, часть вторая 8

Page 25: "Внутренности" CPython, часть II

code object

Код в Python - тоже объект.Интерпретатор оперирует байткодом стековой машины.Инструкции занимают 1 байт, опционально принимают одиндвухбайтный аргумент.Константы сложных типов хранятся “рядом” в code object,обращение к ним происходит по индексу.

“Внутренности” CPython, часть вторая 8

Page 26: "Внутренности" CPython, часть II

code object

def f(x): return (1,2,3)[x] + 1

0 LOAD_CONST 4 ((1, 2, 3))3 LOAD_FAST 0 (x)6 BINARY_SUBSCR7 LOAD_CONST 1 (1)10 BINARY_ADD11 RETURN_VALUE

>>> f.__code__.co_consts(None, 1, 2, 3, (1, 2, 3))

“Внутренности” CPython, часть вторая 9

Page 27: "Внутренности" CPython, часть II

Стеки и фреймы.

“Внутренности” CPython, часть вторая 10

Page 28: "Внутренности" CPython, часть II

Стековая машина

На уровне байткода CPython является стековой машиной.

Значения кладутся на стек, операции берут их с вершины стека,иногда меняя порядок верхних элементов.Стек значений не имеет отношения к стеку адресов возврата - этоотдельная сущность.

“Внутренности” CPython, часть вторая 11

Page 29: "Внутренности" CPython, часть II

Стековая машина

На уровне байткода CPython является стековой машиной.Значения кладутся на стек, операции берут их с вершины стека,иногда меняя порядок верхних элементов.

Стек значений не имеет отношения к стеку адресов возврата - этоотдельная сущность.

“Внутренности” CPython, часть вторая 11

Page 30: "Внутренности" CPython, часть II

Стековая машина

На уровне байткода CPython является стековой машиной.Значения кладутся на стек, операции берут их с вершины стека,иногда меняя порядок верхних элементов.Стек значений не имеет отношения к стеку адресов возврата - этоотдельная сущность.

“Внутренности” CPython, часть вторая 11

Page 31: "Внутренности" CPython, часть II

Стековая машина, пример

def f(a,b,c): return a + b*c

0 LOAD_FAST 0 (a)3 LOAD_FAST 1 (b)6 LOAD_FAST 2 (c)9 BINARY_MULTIPLY10 BINARY_ADD11 RETURN_VALUE

“Внутренности” CPython, часть вторая 12

Page 32: "Внутренности" CPython, часть II

Нелокальный выход

Стек значений (value stack) существует в рамках одногоисполнения code object

Python поддерживает нелокальный выход (break, continue,raise)Необходимо “открутить” стек значений на момент входа в for,while или локальный try

С++ использует для stack unwind при исключениях пометки в“общем” стекеCPython использует для этих целей block stack.

“Внутренности” CPython, часть вторая 13

Page 33: "Внутренности" CPython, часть II

Нелокальный выход

Стек значений (value stack) существует в рамках одногоисполнения code objectPython поддерживает нелокальный выход (break, continue,raise)

Необходимо “открутить” стек значений на момент входа в for,while или локальный try

С++ использует для stack unwind при исключениях пометки в“общем” стекеCPython использует для этих целей block stack.

“Внутренности” CPython, часть вторая 13

Page 34: "Внутренности" CPython, часть II

Нелокальный выход

Стек значений (value stack) существует в рамках одногоисполнения code objectPython поддерживает нелокальный выход (break, continue,raise)Необходимо “открутить” стек значений на момент входа в for,while или локальный try

С++ использует для stack unwind при исключениях пометки в“общем” стекеCPython использует для этих целей block stack.

“Внутренности” CPython, часть вторая 13

Page 35: "Внутренности" CPython, часть II

Нелокальный выход

Стек значений (value stack) существует в рамках одногоисполнения code objectPython поддерживает нелокальный выход (break, continue,raise)Необходимо “открутить” стек значений на момент входа в for,while или локальный try

С++ использует для stack unwind при исключениях пометки в“общем” стеке

CPython использует для этих целей block stack.

“Внутренности” CPython, часть вторая 13

Page 36: "Внутренности" CPython, часть II

Нелокальный выход

Стек значений (value stack) существует в рамках одногоисполнения code objectPython поддерживает нелокальный выход (break, continue,raise)Необходимо “открутить” стек значений на момент входа в for,while или локальный try

С++ использует для stack unwind при исключениях пометки в“общем” стекеCPython использует для этих целей block stack.

“Внутренности” CPython, часть вторая 13

Page 37: "Внутренности" CPython, часть II

Block stack

Block stack хранит в себе пары вида (адрес, глубина стека)

Инструкции вроде break “откручивают” value stack дозапомненного значения глубины и делают goto на указанныйадрес в байткодеДавайте посмотрим как это выглядит

“Внутренности” CPython, часть вторая 14

Page 38: "Внутренности" CPython, часть II

Block stack

Block stack хранит в себе пары вида (адрес, глубина стека)Инструкции вроде break “откручивают” value stack дозапомненного значения глубины и делают goto на указанныйадрес в байткоде

Давайте посмотрим как это выглядит

“Внутренности” CPython, часть вторая 14

Page 39: "Внутренности" CPython, часть II

Block stack

Block stack хранит в себе пары вида (адрес, глубина стека)Инструкции вроде break “откручивают” value stack дозапомненного значения глубины и делают goto на указанныйадрес в байткодеДавайте посмотрим как это выглядит

“Внутренности” CPython, часть вторая 14

Page 40: "Внутренности" CPython, часть II

Block stack, пример

def f():while 1:return 2; continue; break

0 SETUP_LOOP 8 (to 11)>> 3 LOAD_CONST 1 (2)

6 RETURN_VALUE7 BREAK_LOOP8 JUMP_ABSOLUTE 3

>> 11 LOAD_CONST 0 (None)14 RETURN_VALUE

“Внутренности” CPython, часть вторая 15

Page 41: "Внутренности" CPython, часть II

ceval.c

case SETUP_LOOP:case SETUP_EXCEPT:case SETUP_FINALLY:

PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg,STACK_LEVEL());

continue;

“Внутренности” CPython, часть вторая 16

Page 42: "Внутренности" CPython, часть II

ceval.c, BREAK

case BREAK_LOOP:why = WHY_BREAK;goto fast_block_end;

fast_block_end:while (why != WHY_NOT && f->f_iblock > 0) {

PyTryBlock *b = PyFrame_BlockPop(f);

if (b->b_type == SETUP_LOOP && why == WHY_BREAK) {why = WHY_NOT;JUMPTO(b->b_handler);break; }

“Внутренности” CPython, часть вторая 17

Page 43: "Внутренности" CPython, часть II

Другие хранилища

Помимо value stack и block stack, нужно еще хранить адресавозврата, локальные переменные, лексическое замыкание

В прошлой части этой презентации рассказывалось, чтолокальные переменные определяются на этапе компиляции и дляних заводится список фиксированного размера с обращением поиндексу за O(1)

Аналогично компилятор (в байткод) поступает и с лексическимзамыканиемКроме того, code object может вызвать сам себя (рекурсия?) итогда обоим экземплярам нужны свои стеки.

“Внутренности” CPython, часть вторая 18

Page 44: "Внутренности" CPython, часть II

Другие хранилища

Помимо value stack и block stack, нужно еще хранить адресавозврата, локальные переменные, лексическое замыканиеВ прошлой части этой презентации рассказывалось, чтолокальные переменные определяются на этапе компиляции и дляних заводится список фиксированного размера с обращением поиндексу за O(1)

Аналогично компилятор (в байткод) поступает и с лексическимзамыканиемКроме того, code object может вызвать сам себя (рекурсия?) итогда обоим экземплярам нужны свои стеки.

“Внутренности” CPython, часть вторая 18

Page 45: "Внутренности" CPython, часть II

Другие хранилища

Помимо value stack и block stack, нужно еще хранить адресавозврата, локальные переменные, лексическое замыканиеВ прошлой части этой презентации рассказывалось, чтолокальные переменные определяются на этапе компиляции и дляних заводится список фиксированного размера с обращением поиндексу за O(1)

Аналогично компилятор (в байткод) поступает и с лексическимзамыканием

Кроме того, code object может вызвать сам себя (рекурсия?) итогда обоим экземплярам нужны свои стеки.

“Внутренности” CPython, часть вторая 18

Page 46: "Внутренности" CPython, часть II

Другие хранилища

Помимо value stack и block stack, нужно еще хранить адресавозврата, локальные переменные, лексическое замыканиеВ прошлой части этой презентации рассказывалось, чтолокальные переменные определяются на этапе компиляции и дляних заводится список фиксированного размера с обращением поиндексу за O(1)

Аналогично компилятор (в байткод) поступает и с лексическимзамыканиемКроме того, code object может вызвать сам себя (рекурсия?) итогда обоим экземплярам нужны свои стеки.

“Внутренности” CPython, часть вторая 18

Page 47: "Внутренности" CPython, часть II

frame object

Является хранилищем состояния для конкретного code object

Без code object не имеет смысла - все его параметрыопределяются атрибутами исполняемого кодаВключает в себя value stack, block stack, locals, cellvarsСсылается на предыдущий фрейм в стеке

“Внутренности” CPython, часть вторая 19

Page 48: "Внутренности" CPython, часть II

frame object

Является хранилищем состояния для конкретного code objectБез code object не имеет смысла - все его параметрыопределяются атрибутами исполняемого кода

Включает в себя value stack, block stack, locals, cellvarsСсылается на предыдущий фрейм в стеке

“Внутренности” CPython, часть вторая 19

Page 49: "Внутренности" CPython, часть II

frame object

Является хранилищем состояния для конкретного code objectБез code object не имеет смысла - все его параметрыопределяются атрибутами исполняемого кодаВключает в себя value stack, block stack, locals, cellvars

Ссылается на предыдущий фрейм в стеке

“Внутренности” CPython, часть вторая 19

Page 50: "Внутренности" CPython, часть II

frame object

Является хранилищем состояния для конкретного code objectБез code object не имеет смысла - все его параметрыопределяются атрибутами исполняемого кодаВключает в себя value stack, block stack, locals, cellvarsСсылается на предыдущий фрейм в стеке

“Внутренности” CPython, часть вторая 19

Page 51: "Внутренности" CPython, часть II

frame object

frame object - полный аналог activation frame в С

Только в C activation frame расположен на общем стеке - адресавозврата и локальные переменные идут “вперемешку”, и activationframe волей-неволей уничтожается при выходе из функции(последующие вызовы других функций его перетрут).В frame object есть ссылка f_back на предыдущий фрейм в стеке,поэтому в CPython стек вызовов реализован как односвязныйсписок.

“Внутренности” CPython, часть вторая 20

Page 52: "Внутренности" CPython, часть II

frame object

frame object - полный аналог activation frame в СТолько в C activation frame расположен на общем стеке - адресавозврата и локальные переменные идут “вперемешку”, и activationframe волей-неволей уничтожается при выходе из функции(последующие вызовы других функций его перетрут).

В frame object есть ссылка f_back на предыдущий фрейм в стеке,поэтому в CPython стек вызовов реализован как односвязныйсписок.

“Внутренности” CPython, часть вторая 20

Page 53: "Внутренности" CPython, часть II

frame object

frame object - полный аналог activation frame в СТолько в C activation frame расположен на общем стеке - адресавозврата и локальные переменные идут “вперемешку”, и activationframe волей-неволей уничтожается при выходе из функции(последующие вызовы других функций его перетрут).В frame object есть ссылка f_back на предыдущий фрейм в стеке,поэтому в CPython стек вызовов реализован как односвязныйсписок.

“Внутренности” CPython, часть вторая 20

Page 54: "Внутренности" CPython, часть II

Почему односвязный список?

В отличие от contiguous представления стека в C, это позволяетпродлевать время жизни фрейма сколь угодно долго.

Каждый фрейм выделяется и освобождается как обычныйPyObject, в подходящем месте в памяти, совершеннонеобязательно кого-то перетирать.Это позволяет реализовать генераторы.

“Внутренности” CPython, часть вторая 21

Page 55: "Внутренности" CPython, часть II

Почему односвязный список?

В отличие от contiguous представления стека в C, это позволяетпродлевать время жизни фрейма сколь угодно долго.Каждый фрейм выделяется и освобождается как обычныйPyObject, в подходящем месте в памяти, совершеннонеобязательно кого-то перетирать.

Это позволяет реализовать генераторы.

“Внутренности” CPython, часть вторая 21

Page 56: "Внутренности" CPython, часть II

Почему односвязный список?

В отличие от contiguous представления стека в C, это позволяетпродлевать время жизни фрейма сколь угодно долго.Каждый фрейм выделяется и освобождается как обычныйPyObject, в подходящем месте в памяти, совершеннонеобязательно кого-то перетирать.Это позволяет реализовать генераторы.

“Внутренности” CPython, часть вторая 21

Page 57: "Внутренности" CPython, часть II

Генераторы

Это просто стек (в виде списка) фреймов, завернутый в объект(genobject).

yield приостанавливает его выполнение, next() возобновляет cтого места, где в последний раз был вызван yield

Стек фреймов живет столько, сколько живет genobject.

“Внутренности” CPython, часть вторая 22

Page 58: "Внутренности" CPython, часть II

Генераторы

Это просто стек (в виде списка) фреймов, завернутый в объект(genobject).yield приостанавливает его выполнение, next() возобновляет cтого места, где в последний раз был вызван yield

Стек фреймов живет столько, сколько живет genobject.

“Внутренности” CPython, часть вторая 22

Page 59: "Внутренности" CPython, часть II

Генераторы

Это просто стек (в виде списка) фреймов, завернутый в объект(genobject).yield приостанавливает его выполнение, next() возобновляет cтого места, где в последний раз был вызван yield

Стек фреймов живет столько, сколько живет genobject.

“Внутренности” CPython, часть вторая 22

Page 60: "Внутренности" CPython, часть II

Генераторы и фреймы

code 1

code 2

code gencode 3

code 4genobject

f_code

f_back

f_code

locals

f_back

f_code

f_backf_code

f_backf_code

f_backf_code

f_back

f_code

f_back

f_code

f_back

“Внутренности” CPython, часть вторая 23

Page 61: "Внутренности" CPython, часть II

Генераторы

Генераторы в CPython не столь общи, как хотелось бы

Во-первых, yield это statement, а не expressionВо-вторых, yield возможен только в самой функции-генераторе,нo не в вызываемых еюОба ограничения нефундаментальны

“Внутренности” CPython, часть вторая 24

Page 62: "Внутренности" CPython, часть II

Генераторы

Генераторы в CPython не столь общи, как хотелось быВо-первых, yield это statement, а не expression

Во-вторых, yield возможен только в самой функции-генераторе,нo не в вызываемых еюОба ограничения нефундаментальны

“Внутренности” CPython, часть вторая 24

Page 63: "Внутренности" CPython, часть II

Генераторы

Генераторы в CPython не столь общи, как хотелось быВо-первых, yield это statement, а не expressionВо-вторых, yield возможен только в самой функции-генераторе,нo не в вызываемых ею

Оба ограничения нефундаментальны

“Внутренности” CPython, часть вторая 24

Page 64: "Внутренности" CPython, часть II

Генераторы

Генераторы в CPython не столь общи, как хотелось быВо-первых, yield это statement, а не expressionВо-вторых, yield возможен только в самой функции-генераторе,нo не в вызываемых еюОба ограничения нефундаментальны

“Внутренности” CPython, часть вторая 24

Page 65: "Внутренности" CPython, часть II

Генераторы - альтернативы

PEP 380 - официально принятый для Python 3 пропоузал,который позволит реализовывать полноценные сопрограммы нагенераторах (как, например, в Lua)

greenlet - нативный модуль расширения для CPython,реализующий кооперативную многозадачность через “срезание”сишного стекаstackless - форк CPython, развивающий идею “фреймы какобъекты” до полноценной кооперативной многозадачности

“Внутренности” CPython, часть вторая 25

Page 66: "Внутренности" CPython, часть II

Генераторы - альтернативы

PEP 380 - официально принятый для Python 3 пропоузал,который позволит реализовывать полноценные сопрограммы нагенераторах (как, например, в Lua)greenlet - нативный модуль расширения для CPython,реализующий кооперативную многозадачность через “срезание”сишного стека

stackless - форк CPython, развивающий идею “фреймы какобъекты” до полноценной кооперативной многозадачности

“Внутренности” CPython, часть вторая 25

Page 67: "Внутренности" CPython, часть II

Генераторы - альтернативы

PEP 380 - официально принятый для Python 3 пропоузал,который позволит реализовывать полноценные сопрограммы нагенераторах (как, например, в Lua)greenlet - нативный модуль расширения для CPython,реализующий кооперативную многозадачность через “срезание”сишного стекаstackless - форк CPython, развивающий идею “фреймы какобъекты” до полноценной кооперативной многозадачности

“Внутренности” CPython, часть вторая 25

Page 68: "Внутренности" CPython, часть II

Объектная модель

“Внутренности” CPython, часть вторая 26

Page 69: "Внутренности" CPython, часть II

Объектная модель

Ранее мы уже упоминали, что все с точки зрения CPython естьPyObject

Также мы знаем, что в байткоде инструкция BINARY_ADD удаляетдва объекта с вершины стека, складывает их, после чегопомещает результат на вершину стекаСложение для чисел - это сложение, для строк - конкатенация, ивообще мы можем переопределить __add__ у чего угодноКак интерпретатор узнает, что делать?

“Внутренности” CPython, часть вторая 27

Page 70: "Внутренности" CPython, часть II

Объектная модель

Ранее мы уже упоминали, что все с точки зрения CPython естьPyObject

Также мы знаем, что в байткоде инструкция BINARY_ADD удаляетдва объекта с вершины стека, складывает их, после чегопомещает результат на вершину стека

Сложение для чисел - это сложение, для строк - конкатенация, ивообще мы можем переопределить __add__ у чего угодноКак интерпретатор узнает, что делать?

“Внутренности” CPython, часть вторая 27

Page 71: "Внутренности" CPython, часть II

Объектная модель

Ранее мы уже упоминали, что все с точки зрения CPython естьPyObject

Также мы знаем, что в байткоде инструкция BINARY_ADD удаляетдва объекта с вершины стека, складывает их, после чегопомещает результат на вершину стекаСложение для чисел - это сложение, для строк - конкатенация, ивообще мы можем переопределить __add__ у чего угодно

Как интерпретатор узнает, что делать?

“Внутренности” CPython, часть вторая 27

Page 72: "Внутренности" CPython, часть II

Объектная модель

Ранее мы уже упоминали, что все с точки зрения CPython естьPyObject

Также мы знаем, что в байткоде инструкция BINARY_ADD удаляетдва объекта с вершины стека, складывает их, после чегопомещает результат на вершину стекаСложение для чисел - это сложение, для строк - конкатенация, ивообще мы можем переопределить __add__ у чего угодноКак интерпретатор узнает, что делать?

“Внутренности” CPython, часть вторая 27

Page 73: "Внутренности" CPython, часть II

Type object, слоты, протоколы

В самом начале мы упомянули, что у PyObject обязательноприсутствует поле ob_type - ссылка на type object

Оказывается, в type object есть слоты, возвращающие реализациитребуемых операций (если те поддерживаются объектом, самособой)Интерпретатор просто вызывает нужные функции по указателям,либо возвращает ошибку несовместимости типов.Рассмотрим на примере int object.

“Внутренности” CPython, часть вторая 28

Page 74: "Внутренности" CPython, часть II

Type object, слоты, протоколы

В самом начале мы упомянули, что у PyObject обязательноприсутствует поле ob_type - ссылка на type objectОказывается, в type object есть слоты, возвращающие реализациитребуемых операций (если те поддерживаются объектом, самособой)

Интерпретатор просто вызывает нужные функции по указателям,либо возвращает ошибку несовместимости типов.Рассмотрим на примере int object.

“Внутренности” CPython, часть вторая 28

Page 75: "Внутренности" CPython, часть II

Type object, слоты, протоколы

В самом начале мы упомянули, что у PyObject обязательноприсутствует поле ob_type - ссылка на type objectОказывается, в type object есть слоты, возвращающие реализациитребуемых операций (если те поддерживаются объектом, самособой)Интерпретатор просто вызывает нужные функции по указателям,либо возвращает ошибку несовместимости типов.

Рассмотрим на примере int object.

“Внутренности” CPython, часть вторая 28

Page 76: "Внутренности" CPython, часть II

Type object, слоты, протоколы

В самом начале мы упомянули, что у PyObject обязательноприсутствует поле ob_type - ссылка на type objectОказывается, в type object есть слоты, возвращающие реализациитребуемых операций (если те поддерживаются объектом, самособой)Интерпретатор просто вызывает нужные функции по указателям,либо возвращает ошибку несовместимости типов.Рассмотрим на примере int object.

“Внутренности” CPython, часть вторая 28

Page 77: "Внутренности" CPython, часть II

ceval.c

case BINARY_ADD:w = POP();v = TOP();....else {

slow_add:x = PyNumber_Add(v, w);

}...SET_TOP(x);

“Внутренности” CPython, часть вторая 29

Page 78: "Внутренности" CPython, часть II

abstract.c

PyObject * PyNumber_Add(PyObject *v, PyObject *w){

PyObject *result = binary_op1(v, w, NB_SLOT(nb_add));...return result;

}

“Внутренности” CPython, часть вторая 30

Page 79: "Внутренности" CPython, часть II

abstract.c

static PyObject*binary_op1(PyObject *v, PyObject *w, const int op_slot){

binaryfunc slotv = NULL;...slotv = NB_BINOP(v->ob_type->tp_as_number, op_slot);...if (slotv) {

x = slotv(v, w);if (x != Py_NotImplemented)

return x;

“Внутренности” CPython, часть вторая 31

Page 80: "Внутренности" CPython, часть II

intobject.c

static PyObject *int_add(PyIntObject *v, PyIntObject *w){

register long a, b, x;CONVERT_TO_LONG(v, a);CONVERT_TO_LONG(w, b);....x = (long)((unsigned long)a + b);if ((x^a) >= 0 || (x^b) >= 0)

return PyInt_FromLong(x);....

“Внутренности” CPython, часть вторая 32

Page 81: "Внутренности" CPython, часть II

Слоты и протоколы

Слоты и протоколы - это довольно низкоуровневая особенность,которая из кода на Python не видна

Как она сочетается с наследованием и возможностьюпереопределения через “магические” имена (вроде __add__?)В этом проявляется красота объектной модели Python.

“Внутренности” CPython, часть вторая 33

Page 82: "Внутренности" CPython, часть II

Слоты и протоколы

Слоты и протоколы - это довольно низкоуровневая особенность,которая из кода на Python не виднаКак она сочетается с наследованием и возможностьюпереопределения через “магические” имена (вроде __add__?)

В этом проявляется красота объектной модели Python.

“Внутренности” CPython, часть вторая 33

Page 83: "Внутренности" CPython, часть II

Слоты и протоколы

Слоты и протоколы - это довольно низкоуровневая особенность,которая из кода на Python не виднаКак она сочетается с наследованием и возможностьюпереопределения через “магические” имена (вроде __add__?)В этом проявляется красота объектной модели Python.

“Внутренности” CPython, часть вторая 33

Page 84: "Внутренности" CPython, часть II

type object == class

type object и классы - одно и то же.

(За исключением old style classes, которые все являютсяобъектами типа instance и фактически существуют только радисовместимости с legacy кодом на Python < 2.5)При создании класса создается новый type object, которыйнаполняется содержимым из классов-родителей.

“Внутренности” CPython, часть вторая 34

Page 85: "Внутренности" CPython, часть II

type object == class

type object и классы - одно и то же.(За исключением old style classes, которые все являютсяобъектами типа instance и фактически существуют только радисовместимости с legacy кодом на Python < 2.5)

При создании класса создается новый type object, которыйнаполняется содержимым из классов-родителей.

“Внутренности” CPython, часть вторая 34

Page 86: "Внутренности" CPython, часть II

type object == class

type object и классы - одно и то же.(За исключением old style classes, которые все являютсяобъектами типа instance и фактически существуют только радисовместимости с legacy кодом на Python < 2.5)При создании класса создается новый type object, которыйнаполняется содержимым из классов-родителей.

“Внутренности” CPython, часть вторая 34

Page 87: "Внутренности" CPython, часть II

type object == class

При наследовании классов все слоты type object копируются вновый класс (typeobject.c):

static PyObject *type_new(PyTypeObject *metatype,

PyObject *args, PyObject *kwds){

.../* Put the proper slots in place */fixup_slot_dispatchers(type);

“Внутренности” CPython, часть вторая 35

Page 88: "Внутренности" CPython, часть II

type object == class

При попытке переопределить метод в рантайме через выставление“магического” атрибута класса в дело включается type_setattro,определенный в слоте tp_setattro у типа класса

Да, у type object тоже есть тип, и это тоже type object :)type_setattro знает про слоты и правильно их обновляет:

static inttype_setattro(PyTypeObject *type,

PyObject *name, PyObject *value){...return update_slot(type, name);

“Внутренности” CPython, часть вторая 36

Page 89: "Внутренности" CPython, часть II

type object == class

При попытке переопределить метод в рантайме через выставление“магического” атрибута класса в дело включается type_setattro,определенный в слоте tp_setattro у типа классаДа, у type object тоже есть тип, и это тоже type object :)

type_setattro знает про слоты и правильно их обновляет:

static inttype_setattro(PyTypeObject *type,

PyObject *name, PyObject *value){...return update_slot(type, name);

“Внутренности” CPython, часть вторая 36

Page 90: "Внутренности" CPython, часть II

type object == class

При попытке переопределить метод в рантайме через выставление“магического” атрибута класса в дело включается type_setattro,определенный в слоте tp_setattro у типа классаДа, у type object тоже есть тип, и это тоже type object :)type_setattro знает про слоты и правильно их обновляет:

static inttype_setattro(PyTypeObject *type,

PyObject *name, PyObject *value){...return update_slot(type, name);

“Внутренности” CPython, часть вторая 36

Page 91: "Внутренности" CPython, часть II

type object == class

Кроме того, технические поля инстанса (вроде __dict__), такжеявляются с точки зрения типа обычными аттрибутами

Вкупе с дескрипторами, про которые много кто уже здесьговорил, это дает поистине впечатляющие возможностиВ частности, практически ко всему, во что можно впихнутьзаголовок PyObject, можно предоставить идиоматичнуюпитоновскую обертку, не меняя представленияЭто обуславливает такое количество библиотек - делатьинтерфейсы для C/C++ библиотек довольно легко

“Внутренности” CPython, часть вторая 37

Page 92: "Внутренности" CPython, часть II

type object == class

Кроме того, технические поля инстанса (вроде __dict__), такжеявляются с точки зрения типа обычными аттрибутамиВкупе с дескрипторами, про которые много кто уже здесьговорил, это дает поистине впечатляющие возможности

В частности, практически ко всему, во что можно впихнутьзаголовок PyObject, можно предоставить идиоматичнуюпитоновскую обертку, не меняя представленияЭто обуславливает такое количество библиотек - делатьинтерфейсы для C/C++ библиотек довольно легко

“Внутренности” CPython, часть вторая 37

Page 93: "Внутренности" CPython, часть II

type object == class

Кроме того, технические поля инстанса (вроде __dict__), такжеявляются с точки зрения типа обычными аттрибутамиВкупе с дескрипторами, про которые много кто уже здесьговорил, это дает поистине впечатляющие возможностиВ частности, практически ко всему, во что можно впихнутьзаголовок PyObject, можно предоставить идиоматичнуюпитоновскую обертку, не меняя представления

Это обуславливает такое количество библиотек - делатьинтерфейсы для C/C++ библиотек довольно легко

“Внутренности” CPython, часть вторая 37

Page 94: "Внутренности" CPython, часть II

type object == class

Кроме того, технические поля инстанса (вроде __dict__), такжеявляются с точки зрения типа обычными аттрибутамиВкупе с дескрипторами, про которые много кто уже здесьговорил, это дает поистине впечатляющие возможностиВ частности, практически ко всему, во что можно впихнутьзаголовок PyObject, можно предоставить идиоматичнуюпитоновскую обертку, не меняя представленияЭто обуславливает такое количество библиотек - делатьинтерфейсы для C/C++ библиотек довольно легко

“Внутренности” CPython, часть вторая 37

Page 95: "Внутренности" CPython, часть II

slots

Чтобы поменять представление объекта в памяти, необязательнолезть на уровень Python/C API

Для объектов, которые создаются миллионами и редко меняютнабор полей, есть встроенная возможность избежать создания__dict__ для каждого инстанса.Для этого в классе надо объявить атрибут __slots__, и в немобъявить имена полей.Тогда все инстансы будут хранить только ссылки на значенияатрибутов в определенном порядке, __dict__ будет создан толькопри попытке выставить атрибут не из __slots__.

“Внутренности” CPython, часть вторая 38

Page 96: "Внутренности" CPython, часть II

slots

Чтобы поменять представление объекта в памяти, необязательнолезть на уровень Python/C API

Для объектов, которые создаются миллионами и редко меняютнабор полей, есть встроенная возможность избежать создания__dict__ для каждого инстанса.

Для этого в классе надо объявить атрибут __slots__, и в немобъявить имена полей.Тогда все инстансы будут хранить только ссылки на значенияатрибутов в определенном порядке, __dict__ будет создан толькопри попытке выставить атрибут не из __slots__.

“Внутренности” CPython, часть вторая 38

Page 97: "Внутренности" CPython, часть II

slots

Чтобы поменять представление объекта в памяти, необязательнолезть на уровень Python/C API

Для объектов, которые создаются миллионами и редко меняютнабор полей, есть встроенная возможность избежать создания__dict__ для каждого инстанса.Для этого в классе надо объявить атрибут __slots__, и в немобъявить имена полей.

Тогда все инстансы будут хранить только ссылки на значенияатрибутов в определенном порядке, __dict__ будет создан толькопри попытке выставить атрибут не из __slots__.

“Внутренности” CPython, часть вторая 38

Page 98: "Внутренности" CPython, часть II

slots

Чтобы поменять представление объекта в памяти, необязательнолезть на уровень Python/C API

Для объектов, которые создаются миллионами и редко меняютнабор полей, есть встроенная возможность избежать создания__dict__ для каждого инстанса.Для этого в классе надо объявить атрибут __slots__, и в немобъявить имена полей.Тогда все инстансы будут хранить только ссылки на значенияатрибутов в определенном порядке, __dict__ будет создан толькопри попытке выставить атрибут не из __slots__.

“Внутренности” CPython, часть вторая 38

Page 99: "Внутренности" CPython, часть II

slots

>>> class SlotClass: __slots__ = "x", "y">>> X = SlotClass()>>> X.x = 1; X.y = 2>>> asizeof(X)128

>>> class DictClass: pass>>> Y = DictClass()>>> Y.x = 1; Y.y = 2>>> asizeof(Y)480

“Внутренности” CPython, часть вторая 39

Page 100: "Внутренности" CPython, часть II

Заключение

“Внутренности” CPython, часть вторая 40

Page 101: "Внутренности" CPython, часть II

Заключение

Напоследок хочу напомнить, что все рассказанное может бытьпочерпнуто прямо из исходников CPython - они хорошозадокументированы и читаются довольно легко

Лезть в исходники интерпретатора чтобы понять, как ведет себяприкладной код - вполне себе реальный сценарийЕсли тема доклада вас заинтересовала, то от себя хочупорекомендовать следующие ресурсы

“Внутренности” CPython, часть вторая 41

Page 102: "Внутренности" CPython, часть II

Заключение

Напоследок хочу напомнить, что все рассказанное может бытьпочерпнуто прямо из исходников CPython - они хорошозадокументированы и читаются довольно легкоЛезть в исходники интерпретатора чтобы понять, как ведет себяприкладной код - вполне себе реальный сценарий

Если тема доклада вас заинтересовала, то от себя хочупорекомендовать следующие ресурсы

“Внутренности” CPython, часть вторая 41

Page 103: "Внутренности" CPython, часть II

Заключение

Напоследок хочу напомнить, что все рассказанное может бытьпочерпнуто прямо из исходников CPython - они хорошозадокументированы и читаются довольно легкоЛезть в исходники интерпретатора чтобы понять, как ведет себяприкладной код - вполне себе реальный сценарийЕсли тема доклада вас заинтересовала, то от себя хочупорекомендовать следующие ресурсы

“Внутренности” CPython, часть вторая 41

Page 104: "Внутренности" CPython, часть II

“Python Innards”, Yaniv Aknin

http://en.wordpress.com/tag/pythons-innards/Серия постов от Yaniv Aknin про байткод, стеки,thread state и объектную модель в CPython.

“Внутренности” CPython, часть вторая 42

Page 105: "Внутренности" CPython, часть II

“Python internals”, Eli Bendersky

http://tinyurl.com/pyinternalsСерия постов от Eli Bendersky про компиляторPython, а также объектную модель Python 3.

“Внутренности” CPython, часть вторая 43

Page 106: "Внутренности" CPython, часть II

“Understanding the Python GIL”, David Beazley

http://www.dabeaz.com/GIL/Презентации David Beazley, касающиесяособенностей реализации GIL в Python,проливающие свет на его неочевидное поведение(например, существенное замедление CPU-boundмногопоточного кода на многоядерных машинах)

“Внутренности” CPython, часть вторая 44

Page 107: "Внутренности" CPython, часть II

Благодарю за внимание!

Page 108: "Внутренности" CPython, часть II

Вопросы?