Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

2,349 views

Published on

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

Published in: Technology
  • Be the first to comment

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

  1. 1. “Внутренности” CPython, часть вторая Никита Лесников
  2. 2. Вспомнить все. “Внутренности” CPython, часть вторая 2
  3. 3. Вспомнить все Наверняка не все присутствовали на первой части моего выступления “Внутренности” CPython, часть вторая 3
  4. 4. Вспомнить все Наверняка не все присутствовали на первой части моего выступления Это ведь было аж в июне “Внутренности” CPython, часть вторая 3
  5. 5. Вспомнить все Наверняка не все присутствовали на первой части моего выступления Это ведь было аж в июне Поэтому кратко повторю, о чем мы собираемся разговаривать “Внутренности” CPython, часть вторая 3
  6. 6. CPython Основная реализация на сегодняшний день “Внутренности” CPython, часть вторая 4
  7. 7. CPython Основная реализация на сегодняшний день Написана на C “Внутренности” CPython, часть вторая 4
  8. 8. CPython Основная реализация на сегодняшний день Написана на C “Чистый” интерпретатор байткода, без JIT и AOT “Внутренности” CPython, часть вторая 4
  9. 9. CPython Основная реализация на сегодняшний день Написана на C “Чистый” интерпретатор байткода, без JIT и AOT “Своя” VM, никаких отсылок к Java и .NET “Внутренности” CPython, часть вторая 4
  10. 10. Альтернативы native+ - PyPy “Внутренности” CPython, часть вторая 5
  11. 11. Альтернативы native+ - PyPy .NET - IronPython, Boo (правда, строго говоря это не Python) “Внутренности” CPython, часть вторая 5
  12. 12. Альтернативы native+ - PyPy .NET - IronPython, Boo (правда, строго говоря это не Python) JVM - Jython “Внутренности” CPython, часть вторая 5
  13. 13. Альтернативы native+ - PyPy .NET - IronPython, Boo (правда, строго говоря это не Python) JVM - Jython Возможно другие. Они нас сегодня не интересуют. “Внутренности” CPython, часть вторая 5
  14. 14. Альтернативы native+ - PyPy .NET - IronPython, Boo (правда, строго говоря это не Python) JVM - Jython Возможно другие. Они нас сегодня не интересуют. Мы рассматриваем внутреннее устройство CPython. “Внутренности” CPython, часть вторая 5
  15. 15. Все - объект В CPython все является объектом “Внутренности” CPython, часть вторая 6
  16. 16. Все - объект В CPython все является объектом Конкретнее - PyObject* “Внутренности” CPython, часть вторая 6
  17. 17. Все - объект В CPython все является объектом Конкретнее - PyObject* Числа, строки, код, фреймы, модули - абсолютно все “Внутренности” CPython, часть вторая 6
  18. 18. Все - объект В CPython все является объектом Конкретнее - PyObject* Числа, строки, код, фреймы, модули - абсолютно все Любой PyObject начинается одинаково: #define PyObject_HEAD Py_ssize_t ob_refcnt; struct _typeobject *ob_type; “Внутренности” CPython, часть вторая 6
  19. 19. PyObject #define PyObject_HEAD Py_ssize_t ob_refcnt; struct _typeobject *ob_type; ob_refcnt - reference count для управления памятью “Внутренности” CPython, часть вторая 7
  20. 20. PyObject #define PyObject_HEAD Py_ssize_t ob_refcnt; struct _typeobject *ob_type; ob_refcnt - reference count для управления памятью ob_type - type object, задающий поведение конкретного объекта “Внутренности” CPython, часть вторая 7
  21. 21. PyObject #define PyObject_HEAD Py_ssize_t ob_refcnt; struct _typeobject *ob_type; ob_refcnt - reference count для управления памятью ob_type - type object, задающий поведение конкретного объекта То, что дальше, может быть чем угодно. “Внутренности” CPython, часть вторая 7
  22. 22. code object Код в Python - тоже объект. “Внутренности” CPython, часть вторая 8
  23. 23. code object Код в Python - тоже объект. Интерпретатор оперирует байткодом стековой машины. “Внутренности” CPython, часть вторая 8
  24. 24. code object Код в Python - тоже объект. Интерпретатор оперирует байткодом стековой машины. Инструкции занимают 1 байт, опционально принимают один двухбайтный аргумент. “Внутренности” CPython, часть вторая 8
  25. 25. code object Код в Python - тоже объект. Интерпретатор оперирует байткодом стековой машины. Инструкции занимают 1 байт, опционально принимают один двухбайтный аргумент. Константы сложных типов хранятся “рядом” в code object, обращение к ним происходит по индексу. “Внутренности” CPython, часть вторая 8
  26. 26. 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_SUBSCR 7 LOAD_CONST 1 (1) 10 BINARY_ADD 11 RETURN_VALUE >>> f.__code__.co_consts (None, 1, 2, 3, (1, 2, 3)) “Внутренности” CPython, часть вторая 9
  27. 27. Стеки и фреймы. “Внутренности” CPython, часть вторая 10
  28. 28. Стековая машина На уровне байткода CPython является стековой машиной. “Внутренности” CPython, часть вторая 11
  29. 29. Стековая машина На уровне байткода CPython является стековой машиной. Значения кладутся на стек, операции берут их с вершины стека, иногда меняя порядок верхних элементов. “Внутренности” CPython, часть вторая 11
  30. 30. Стековая машина На уровне байткода CPython является стековой машиной. Значения кладутся на стек, операции берут их с вершины стека, иногда меняя порядок верхних элементов. Стек значений не имеет отношения к стеку адресов возврата - это отдельная сущность. “Внутренности” CPython, часть вторая 11
  31. 31. Стековая машина, пример 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_MULTIPLY 10 BINARY_ADD 11 RETURN_VALUE “Внутренности” CPython, часть вторая 12
  32. 32. Нелокальный выход Стек значений (value stack) существует в рамках одного исполнения code object “Внутренности” CPython, часть вторая 13
  33. 33. Нелокальный выход Стек значений (value stack) существует в рамках одного исполнения code object Python поддерживает нелокальный выход (break, continue, raise) “Внутренности” CPython, часть вторая 13
  34. 34. Нелокальный выход Стек значений (value stack) существует в рамках одного исполнения code object Python поддерживает нелокальный выход (break, continue, raise) Необходимо “открутить” стек значений на момент входа в for, while или локальный try “Внутренности” CPython, часть вторая 13
  35. 35. Нелокальный выход Стек значений (value stack) существует в рамках одного исполнения code object Python поддерживает нелокальный выход (break, continue, raise) Необходимо “открутить” стек значений на момент входа в for, while или локальный try С++ использует для stack unwind при исключениях пометки в “общем” стеке “Внутренности” CPython, часть вторая 13
  36. 36. Нелокальный выход Стек значений (value stack) существует в рамках одного исполнения code object Python поддерживает нелокальный выход (break, continue, raise) Необходимо “открутить” стек значений на момент входа в for, while или локальный try С++ использует для stack unwind при исключениях пометки в “общем” стеке CPython использует для этих целей block stack. “Внутренности” CPython, часть вторая 13
  37. 37. Block stack Block stack хранит в себе пары вида (адрес, глубина стека) “Внутренности” CPython, часть вторая 14
  38. 38. Block stack Block stack хранит в себе пары вида (адрес, глубина стека) Инструкции вроде break “откручивают” value stack до запомненного значения глубины и делают goto на указанный адрес в байткоде “Внутренности” CPython, часть вторая 14
  39. 39. Block stack Block stack хранит в себе пары вида (адрес, глубина стека) Инструкции вроде break “откручивают” value stack до запомненного значения глубины и делают goto на указанный адрес в байткоде Давайте посмотрим как это выглядит “Внутренности” CPython, часть вторая 14
  40. 40. Block stack, пример def f(): while 1: return 2; continue; break 0 SETUP_LOOP 8 (to 11) >> 3 LOAD_CONST 1 (2) 6 RETURN_VALUE 7 BREAK_LOOP 8 JUMP_ABSOLUTE 3 >> 11 LOAD_CONST 0 (None) 14 RETURN_VALUE “Внутренности” CPython, часть вторая 15
  41. 41. ceval.c case SETUP_LOOP: case SETUP_EXCEPT: case SETUP_FINALLY: PyFrame_BlockSetup(f, opcode, INSTR_OFFSET() + oparg, STACK_LEVEL()); continue; “Внутренности” CPython, часть вторая 16
  42. 42. 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
  43. 43. Другие хранилища Помимо value stack и block stack, нужно еще хранить адреса возврата, локальные переменные, лексическое замыкание “Внутренности” CPython, часть вторая 18
  44. 44. Другие хранилища Помимо value stack и block stack, нужно еще хранить адреса возврата, локальные переменные, лексическое замыкание В прошлой части этой презентации рассказывалось, что локальные переменные определяются на этапе компиляции и для них заводится список фиксированного размера с обращением по индексу за O(1) “Внутренности” CPython, часть вторая 18
  45. 45. Другие хранилища Помимо value stack и block stack, нужно еще хранить адреса возврата, локальные переменные, лексическое замыкание В прошлой части этой презентации рассказывалось, что локальные переменные определяются на этапе компиляции и для них заводится список фиксированного размера с обращением по индексу за O(1) Аналогично компилятор (в байткод) поступает и с лексическим замыканием “Внутренности” CPython, часть вторая 18
  46. 46. Другие хранилища Помимо value stack и block stack, нужно еще хранить адреса возврата, локальные переменные, лексическое замыкание В прошлой части этой презентации рассказывалось, что локальные переменные определяются на этапе компиляции и для них заводится список фиксированного размера с обращением по индексу за O(1) Аналогично компилятор (в байткод) поступает и с лексическим замыканием Кроме того, code object может вызвать сам себя (рекурсия?) и тогда обоим экземплярам нужны свои стеки. “Внутренности” CPython, часть вторая 18
  47. 47. frame object Является хранилищем состояния для конкретного code object “Внутренности” CPython, часть вторая 19
  48. 48. frame object Является хранилищем состояния для конкретного code object Без code object не имеет смысла - все его параметры определяются атрибутами исполняемого кода “Внутренности” CPython, часть вторая 19
  49. 49. frame object Является хранилищем состояния для конкретного code object Без code object не имеет смысла - все его параметры определяются атрибутами исполняемого кода Включает в себя value stack, block stack, locals, cellvars “Внутренности” CPython, часть вторая 19
  50. 50. frame object Является хранилищем состояния для конкретного code object Без code object не имеет смысла - все его параметры определяются атрибутами исполняемого кода Включает в себя value stack, block stack, locals, cellvars Ссылается на предыдущий фрейм в стеке “Внутренности” CPython, часть вторая 19
  51. 51. frame object frame object - полный аналог activation frame в С “Внутренности” CPython, часть вторая 20
  52. 52. frame object frame object - полный аналог activation frame в С Только в C activation frame расположен на общем стеке - адреса возврата и локальные переменные идут “вперемешку”, и activation frame волей-неволей уничтожается при выходе из функции (последующие вызовы других функций его перетрут). “Внутренности” CPython, часть вторая 20
  53. 53. frame object frame object - полный аналог activation frame в С Только в C activation frame расположен на общем стеке - адреса возврата и локальные переменные идут “вперемешку”, и activation frame волей-неволей уничтожается при выходе из функции (последующие вызовы других функций его перетрут). В frame object есть ссылка f_back на предыдущий фрейм в стеке, поэтому в CPython стек вызовов реализован как односвязный список. “Внутренности” CPython, часть вторая 20
  54. 54. Почему односвязный список? В отличие от contiguous представления стека в C, это позволяет продлевать время жизни фрейма сколь угодно долго. “Внутренности” CPython, часть вторая 21
  55. 55. Почему односвязный список? В отличие от contiguous представления стека в C, это позволяет продлевать время жизни фрейма сколь угодно долго. Каждый фрейм выделяется и освобождается как обычный PyObject, в подходящем месте в памяти, совершенно необязательно кого-то перетирать. “Внутренности” CPython, часть вторая 21
  56. 56. Почему односвязный список? В отличие от contiguous представления стека в C, это позволяет продлевать время жизни фрейма сколь угодно долго. Каждый фрейм выделяется и освобождается как обычный PyObject, в подходящем месте в памяти, совершенно необязательно кого-то перетирать. Это позволяет реализовать генераторы. “Внутренности” CPython, часть вторая 21
  57. 57. Генераторы Это просто стек (в виде списка) фреймов, завернутый в объект (genobject). “Внутренности” CPython, часть вторая 22
  58. 58. Генераторы Это просто стек (в виде списка) фреймов, завернутый в объект (genobject). yield приостанавливает его выполнение, next() возобновляет c того места, где в последний раз был вызван yield “Внутренности” CPython, часть вторая 22
  59. 59. Генераторы Это просто стек (в виде списка) фреймов, завернутый в объект (genobject). yield приостанавливает его выполнение, next() возобновляет c того места, где в последний раз был вызван yield Стек фреймов живет столько, сколько живет genobject. “Внутренности” CPython, часть вторая 22
  60. 60. Генераторы и фреймы code 1 code 2 code gencode 3 code 4 genobject f_code f_back f_code locals f_back f_code f_back f_code f_back f_code f_back f_code f_back f_code f_back f_code f_back “Внутренности” CPython, часть вторая 23
  61. 61. Генераторы Генераторы в CPython не столь общи, как хотелось бы “Внутренности” CPython, часть вторая 24
  62. 62. Генераторы Генераторы в CPython не столь общи, как хотелось бы Во-первых, yield это statement, а не expression “Внутренности” CPython, часть вторая 24
  63. 63. Генераторы Генераторы в CPython не столь общи, как хотелось бы Во-первых, yield это statement, а не expression Во-вторых, yield возможен только в самой функции-генераторе, нo не в вызываемых ею “Внутренности” CPython, часть вторая 24
  64. 64. Генераторы Генераторы в CPython не столь общи, как хотелось бы Во-первых, yield это statement, а не expression Во-вторых, yield возможен только в самой функции-генераторе, нo не в вызываемых ею Оба ограничения нефундаментальны “Внутренности” CPython, часть вторая 24
  65. 65. Генераторы - альтернативы PEP 380 - официально принятый для Python 3 пропоузал, который позволит реализовывать полноценные сопрограммы на генераторах (как, например, в Lua) “Внутренности” CPython, часть вторая 25
  66. 66. Генераторы - альтернативы PEP 380 - официально принятый для Python 3 пропоузал, который позволит реализовывать полноценные сопрограммы на генераторах (как, например, в Lua) greenlet - нативный модуль расширения для CPython, реализующий кооперативную многозадачность через “срезание” сишного стека “Внутренности” CPython, часть вторая 25
  67. 67. Генераторы - альтернативы PEP 380 - официально принятый для Python 3 пропоузал, который позволит реализовывать полноценные сопрограммы на генераторах (как, например, в Lua) greenlet - нативный модуль расширения для CPython, реализующий кооперативную многозадачность через “срезание” сишного стека stackless - форк CPython, развивающий идею “фреймы как объекты” до полноценной кооперативной многозадачности “Внутренности” CPython, часть вторая 25
  68. 68. Объектная модель “Внутренности” CPython, часть вторая 26
  69. 69. Объектная модель Ранее мы уже упоминали, что все с точки зрения CPython есть PyObject “Внутренности” CPython, часть вторая 27
  70. 70. Объектная модель Ранее мы уже упоминали, что все с точки зрения CPython есть PyObject Также мы знаем, что в байткоде инструкция BINARY_ADD удаляет два объекта с вершины стека, складывает их, после чего помещает результат на вершину стека “Внутренности” CPython, часть вторая 27
  71. 71. Объектная модель Ранее мы уже упоминали, что все с точки зрения CPython есть PyObject Также мы знаем, что в байткоде инструкция BINARY_ADD удаляет два объекта с вершины стека, складывает их, после чего помещает результат на вершину стека Сложение для чисел - это сложение, для строк - конкатенация, и вообще мы можем переопределить __add__ у чего угодно “Внутренности” CPython, часть вторая 27
  72. 72. Объектная модель Ранее мы уже упоминали, что все с точки зрения CPython есть PyObject Также мы знаем, что в байткоде инструкция BINARY_ADD удаляет два объекта с вершины стека, складывает их, после чего помещает результат на вершину стека Сложение для чисел - это сложение, для строк - конкатенация, и вообще мы можем переопределить __add__ у чего угодно Как интерпретатор узнает, что делать? “Внутренности” CPython, часть вторая 27
  73. 73. Type object, слоты, протоколы В самом начале мы упомянули, что у PyObject обязательно присутствует поле ob_type - ссылка на type object “Внутренности” CPython, часть вторая 28
  74. 74. Type object, слоты, протоколы В самом начале мы упомянули, что у PyObject обязательно присутствует поле ob_type - ссылка на type object Оказывается, в type object есть слоты, возвращающие реализации требуемых операций (если те поддерживаются объектом, само собой) “Внутренности” CPython, часть вторая 28
  75. 75. Type object, слоты, протоколы В самом начале мы упомянули, что у PyObject обязательно присутствует поле ob_type - ссылка на type object Оказывается, в type object есть слоты, возвращающие реализации требуемых операций (если те поддерживаются объектом, само собой) Интерпретатор просто вызывает нужные функции по указателям, либо возвращает ошибку несовместимости типов. “Внутренности” CPython, часть вторая 28
  76. 76. Type object, слоты, протоколы В самом начале мы упомянули, что у PyObject обязательно присутствует поле ob_type - ссылка на type object Оказывается, в type object есть слоты, возвращающие реализации требуемых операций (если те поддерживаются объектом, само собой) Интерпретатор просто вызывает нужные функции по указателям, либо возвращает ошибку несовместимости типов. Рассмотрим на примере int object. “Внутренности” CPython, часть вторая 28
  77. 77. ceval.c case BINARY_ADD: w = POP(); v = TOP(); .... else { slow_add: x = PyNumber_Add(v, w); } ... SET_TOP(x); “Внутренности” CPython, часть вторая 29
  78. 78. abstract.c PyObject * PyNumber_Add(PyObject *v, PyObject *w) { PyObject *result = binary_op1(v, w, NB_SLOT(nb_add)); ... return result; } “Внутренности” CPython, часть вторая 30
  79. 79. 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
  80. 80. 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
  81. 81. Слоты и протоколы Слоты и протоколы - это довольно низкоуровневая особенность, которая из кода на Python не видна “Внутренности” CPython, часть вторая 33
  82. 82. Слоты и протоколы Слоты и протоколы - это довольно низкоуровневая особенность, которая из кода на Python не видна Как она сочетается с наследованием и возможностью переопределения через “магические” имена (вроде __add__?) “Внутренности” CPython, часть вторая 33
  83. 83. Слоты и протоколы Слоты и протоколы - это довольно низкоуровневая особенность, которая из кода на Python не видна Как она сочетается с наследованием и возможностью переопределения через “магические” имена (вроде __add__?) В этом проявляется красота объектной модели Python. “Внутренности” CPython, часть вторая 33
  84. 84. type object == class type object и классы - одно и то же. “Внутренности” CPython, часть вторая 34
  85. 85. type object == class type object и классы - одно и то же. (За исключением old style classes, которые все являются объектами типа instance и фактически существуют только ради совместимости с legacy кодом на Python < 2.5) “Внутренности” CPython, часть вторая 34
  86. 86. type object == class type object и классы - одно и то же. (За исключением old style classes, которые все являются объектами типа instance и фактически существуют только ради совместимости с legacy кодом на Python < 2.5) При создании класса создается новый type object, который наполняется содержимым из классов-родителей. “Внутренности” CPython, часть вторая 34
  87. 87. 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
  88. 88. type object == class При попытке переопределить метод в рантайме через выставление “магического” атрибута класса в дело включается type_setattro, определенный в слоте tp_setattro у типа класса “Внутренности” CPython, часть вторая 36
  89. 89. type object == class При попытке переопределить метод в рантайме через выставление “магического” атрибута класса в дело включается type_setattro, определенный в слоте tp_setattro у типа класса Да, у type object тоже есть тип, и это тоже type object :) “Внутренности” CPython, часть вторая 36
  90. 90. type object == class При попытке переопределить метод в рантайме через выставление “магического” атрибута класса в дело включается type_setattro, определенный в слоте tp_setattro у типа класса Да, у type object тоже есть тип, и это тоже type object :) type_setattro знает про слоты и правильно их обновляет: static int type_setattro(PyTypeObject *type, PyObject *name, PyObject *value) { ... return update_slot(type, name); “Внутренности” CPython, часть вторая 36
  91. 91. type object == class Кроме того, технические поля инстанса (вроде __dict__), также являются с точки зрения типа обычными аттрибутами “Внутренности” CPython, часть вторая 37
  92. 92. type object == class Кроме того, технические поля инстанса (вроде __dict__), также являются с точки зрения типа обычными аттрибутами Вкупе с дескрипторами, про которые много кто уже здесь говорил, это дает поистине впечатляющие возможности “Внутренности” CPython, часть вторая 37
  93. 93. type object == class Кроме того, технические поля инстанса (вроде __dict__), также являются с точки зрения типа обычными аттрибутами Вкупе с дескрипторами, про которые много кто уже здесь говорил, это дает поистине впечатляющие возможности В частности, практически ко всему, во что можно впихнуть заголовок PyObject, можно предоставить идиоматичную питоновскую обертку, не меняя представления “Внутренности” CPython, часть вторая 37
  94. 94. type object == class Кроме того, технические поля инстанса (вроде __dict__), также являются с точки зрения типа обычными аттрибутами Вкупе с дескрипторами, про которые много кто уже здесь говорил, это дает поистине впечатляющие возможности В частности, практически ко всему, во что можно впихнуть заголовок PyObject, можно предоставить идиоматичную питоновскую обертку, не меняя представления Это обуславливает такое количество библиотек - делать интерфейсы для C/C++ библиотек довольно легко “Внутренности” CPython, часть вторая 37
  95. 95. slots Чтобы поменять представление объекта в памяти, необязательно лезть на уровень Python/C API “Внутренности” CPython, часть вторая 38
  96. 96. slots Чтобы поменять представление объекта в памяти, необязательно лезть на уровень Python/C API Для объектов, которые создаются миллионами и редко меняют набор полей, есть встроенная возможность избежать создания __dict__ для каждого инстанса. “Внутренности” CPython, часть вторая 38
  97. 97. slots Чтобы поменять представление объекта в памяти, необязательно лезть на уровень Python/C API Для объектов, которые создаются миллионами и редко меняют набор полей, есть встроенная возможность избежать создания __dict__ для каждого инстанса. Для этого в классе надо объявить атрибут __slots__, и в нем объявить имена полей. “Внутренности” CPython, часть вторая 38
  98. 98. slots Чтобы поменять представление объекта в памяти, необязательно лезть на уровень Python/C API Для объектов, которые создаются миллионами и редко меняют набор полей, есть встроенная возможность избежать создания __dict__ для каждого инстанса. Для этого в классе надо объявить атрибут __slots__, и в нем объявить имена полей. Тогда все инстансы будут хранить только ссылки на значения атрибутов в определенном порядке, __dict__ будет создан только при попытке выставить атрибут не из __slots__. “Внутренности” CPython, часть вторая 38
  99. 99. 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
  100. 100. Заключение “Внутренности” CPython, часть вторая 40
  101. 101. Заключение Напоследок хочу напомнить, что все рассказанное может быть почерпнуто прямо из исходников CPython - они хорошо задокументированы и читаются довольно легко “Внутренности” CPython, часть вторая 41
  102. 102. Заключение Напоследок хочу напомнить, что все рассказанное может быть почерпнуто прямо из исходников CPython - они хорошо задокументированы и читаются довольно легко Лезть в исходники интерпретатора чтобы понять, как ведет себя прикладной код - вполне себе реальный сценарий “Внутренности” CPython, часть вторая 41
  103. 103. Заключение Напоследок хочу напомнить, что все рассказанное может быть почерпнуто прямо из исходников CPython - они хорошо задокументированы и читаются довольно легко Лезть в исходники интерпретатора чтобы понять, как ведет себя прикладной код - вполне себе реальный сценарий Если тема доклада вас заинтересовала, то от себя хочу порекомендовать следующие ресурсы “Внутренности” CPython, часть вторая 41
  104. 104. “Python Innards”, Yaniv Aknin http://en.wordpress.com/tag/pythons-innards/ Серия постов от Yaniv Aknin про байткод, стеки, thread state и объектную модель в CPython. “Внутренности” CPython, часть вторая 42
  105. 105. “Python internals”, Eli Bendersky http://tinyurl.com/pyinternals Серия постов от Eli Bendersky про компилятор Python, а также объектную модель Python 3. “Внутренности” CPython, часть вторая 43
  106. 106. “Understanding the Python GIL”, David Beazley http://www.dabeaz.com/GIL/ Презентации David Beazley, касающиеся особенностей реализации GIL в Python, проливающие свет на его неочевидное поведение (например, существенное замедление CPU-bound многопоточного кода на многоядерных машинах) “Внутренности” CPython, часть вторая 44
  107. 107. Благодарю за внимание!
  108. 108. Вопросы?

×