123
Беглый обзор “внутренностей” Python Никита Лесников

Беглый обзор "внутренностей" Python

Embed Size (px)

DESCRIPTION

Никита Лесников Беглый обзор "внутренностей" Python

Citation preview

Page 1: Беглый обзор "внутренностей" Python

Беглый обзор “внутренностей” PythonНикита Лесников

Page 2: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Часто у программиста, использующего в работе Python, возникаетодин из следующих вопросов:

какой из двух способов решения проблемы потребляет меньшепамяти?

какой из двух способов работает быстрее?как поведет себя определенная конструкция при измененииruntime среды?

Беглый обзор “внутренностей” Python 2

Page 3: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Часто у программиста, использующего в работе Python, возникаетодин из следующих вопросов:

какой из двух способов решения проблемы потребляет меньшепамяти?какой из двух способов работает быстрее?

как поведет себя определенная конструкция при измененииruntime среды?

Беглый обзор “внутренностей” Python 2

Page 4: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Часто у программиста, использующего в работе Python, возникаетодин из следующих вопросов:

какой из двух способов решения проблемы потребляет меньшепамяти?какой из двух способов работает быстрее?как поведет себя определенная конструкция при измененииruntime среды?

Беглый обзор “внутренностей” Python 2

Page 5: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Решаются они обычно одним из следующих способов:можно спросить у коллег

можно найти ответ на StackOverflowможно замерить самому

Беглый обзор “внутренностей” Python 3

Page 6: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Решаются они обычно одним из следующих способов:можно спросить у коллегможно найти ответ на StackOverflow

можно замерить самому

Беглый обзор “внутренностей” Python 3

Page 7: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Решаются они обычно одним из следующих способов:можно спросить у коллегможно найти ответ на StackOverflowможно замерить самому

Беглый обзор “внутренностей” Python 3

Page 8: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Однако понимание того, как работает интерпретатор на самыхнижних уровнях, позволяет обрести интуитивное пониманиенюансов работы многих конструкций языка.

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

Беглый обзор “внутренностей” Python 4

Page 9: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Однако понимание того, как работает интерпретатор на самыхнижних уровнях, позволяет обрести интуитивное пониманиенюансов работы многих конструкций языка.Кроме того, в случае с Python абсолютное большинствопрограммистов обладает достаточной квалификацией, чтобы безпосредников найти ответ на свой вопрос в исходникахинтерпретатора.

Беглый обзор “внутренностей” Python 4

Page 10: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Знакомство с “внутренностями” полезно также потому, что Pythonявляется open source проектом - кто знает, быть может именно вырешите одну из наболевших проблем? ;)

Кратким изучением наиболее характерных особенностейинтерпретатора мы сейчас и займемся.

Беглый обзор “внутренностей” Python 5

Page 11: Беглый обзор "внутренностей" Python

Почему это может быть полезно?

Знакомство с “внутренностями” полезно также потому, что Pythonявляется open source проектом - кто знает, быть может именно вырешите одну из наболевших проблем? ;)Кратким изучением наиболее характерных особенностейинтерпретатора мы сейчас и займемся.

Беглый обзор “внутренностей” Python 5

Page 12: Беглый обзор "внутренностей" Python

CPython

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

Написана на C (не С++), кроссплатформенна и довольно легкопереносима на отличные от официально поддерживаемыхплатформыКод простой и понятныйНет, серьезно, простой и понятный, даже для людей, неинтересующихся разработкой языков программирования ;)

Беглый обзор “внутренностей” Python 6

Page 13: Беглый обзор "внутренностей" Python

CPython

Основная реализация Python на сегодняшний деньНаписана на C (не С++), кроссплатформенна и довольно легкопереносима на отличные от официально поддерживаемыхплатформы

Код простой и понятныйНет, серьезно, простой и понятный, даже для людей, неинтересующихся разработкой языков программирования ;)

Беглый обзор “внутренностей” Python 6

Page 14: Беглый обзор "внутренностей" Python

CPython

Основная реализация Python на сегодняшний деньНаписана на C (не С++), кроссплатформенна и довольно легкопереносима на отличные от официально поддерживаемыхплатформыКод простой и понятный

Нет, серьезно, простой и понятный, даже для людей, неинтересующихся разработкой языков программирования ;)

Беглый обзор “внутренностей” Python 6

Page 15: Беглый обзор "внутренностей" Python

CPython

Основная реализация Python на сегодняшний деньНаписана на C (не С++), кроссплатформенна и довольно легкопереносима на отличные от официально поддерживаемыхплатформыКод простой и понятныйНет, серьезно, простой и понятный, даже для людей, неинтересующихся разработкой языков программирования ;)

Беглый обзор “внутренностей” Python 6

Page 16: Беглый обзор "внутренностей" Python

CPython

Есть еще PyPy, IronPython, Jython, Boo (хотя это не совсемPython)

Они по своему интересны, но с CPython “внутри” у них малообщегоПоэтому хотя они и могут быть очень полезны на практике,рассматривать их мы не будем

Беглый обзор “внутренностей” Python 7

Page 17: Беглый обзор "внутренностей" Python

CPython

Есть еще PyPy, IronPython, Jython, Boo (хотя это не совсемPython)Они по своему интересны, но с CPython “внутри” у них малообщего

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

Беглый обзор “внутренностей” Python 7

Page 18: Беглый обзор "внутренностей" Python

CPython

Есть еще PyPy, IronPython, Jython, Boo (хотя это не совсемPython)Они по своему интересны, но с CPython “внутри” у них малообщегоПоэтому хотя они и могут быть очень полезны на практике,рассматривать их мы не будем

Беглый обзор “внутренностей” Python 7

Page 19: Беглый обзор "внутренностей" Python

Все - объект.

Беглый обзор “внутренностей” Python 8

Page 20: Беглый обзор "внутренностей" Python

Все - объект

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

Ну то есть вообще все - от чисел до стакфреймовНа C-уровне это выражено типом PyObject *

Любой PyObject имеет стандартный заголовок:

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

Поэтому в 64-битном Python число не может быть меньше 24байт. Deal with it.

Беглый обзор “внутренностей” Python 9

Page 21: Беглый обзор "внутренностей" Python

Все - объект

В Python все является объектомНу то есть вообще все - от чисел до стакфреймов

На C-уровне это выражено типом PyObject *

Любой PyObject имеет стандартный заголовок:

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

Поэтому в 64-битном Python число не может быть меньше 24байт. Deal with it.

Беглый обзор “внутренностей” Python 9

Page 22: Беглый обзор "внутренностей" Python

Все - объект

В Python все является объектомНу то есть вообще все - от чисел до стакфреймовНа C-уровне это выражено типом PyObject *

Любой PyObject имеет стандартный заголовок:

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

Поэтому в 64-битном Python число не может быть меньше 24байт. Deal with it.

Беглый обзор “внутренностей” Python 9

Page 23: Беглый обзор "внутренностей" Python

Все - объект

В Python все является объектомНу то есть вообще все - от чисел до стакфреймовНа C-уровне это выражено типом PyObject *

Любой PyObject имеет стандартный заголовок:

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

Поэтому в 64-битном Python число не может быть меньше 24байт. Deal with it.

Беглый обзор “внутренностей” Python 9

Page 24: Беглый обзор "внутренностей" Python

Все - объект

В Python все является объектомНу то есть вообще все - от чисел до стакфреймовНа C-уровне это выражено типом PyObject *

Любой PyObject имеет стандартный заголовок:

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

Поэтому в 64-битном Python число не может быть меньше 24байт. Deal with it.

Беглый обзор “внутренностей” Python 9

Page 25: Беглый обзор "внутренностей" Python

PyObject *

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

ob_refcnt - reference counterob_type - type object, определяющий поведение объекта изначение полей struct’а, идущих после заголовка (например,PyStringObject, PyIntObject)

PyObject * - указатель. Поэтому все значения в Python передаютсяпо ссылке. No exceptions.

Беглый обзор “внутренностей” Python 10

Page 26: Беглый обзор "внутренностей" Python

Ссылки

PyIntTypeObject

PyIntObject

ob_refcnt = 3

ob_type

ob_ival = 42

a b c

>>> a = b = c = 42

Все три имени ссылаются на одинобъектЭтот факт можно установить припомощи is

В общем случае == и is неэквивалентны

Беглый обзор “внутренностей” Python 11

Page 27: Беглый обзор "внутренностей" Python

None

None - особый объект

Он один на каждый инстанс интерпретатора. Совсем один.Поэтому для него is и == всегда эквивалентны.Вот так вот делать не стоит:

if x == None:

это медленно, бессмысленно и вообще плохой тон.

Беглый обзор “внутренностей” Python 12

Page 28: Беглый обзор "внутренностей" Python

None

None - особый объектОн один на каждый инстанс интерпретатора. Совсем один.

Поэтому для него is и == всегда эквивалентны.Вот так вот делать не стоит:

if x == None:

это медленно, бессмысленно и вообще плохой тон.

Беглый обзор “внутренностей” Python 12

Page 29: Беглый обзор "внутренностей" Python

None

None - особый объектОн один на каждый инстанс интерпретатора. Совсем один.Поэтому для него is и == всегда эквивалентны.

Вот так вот делать не стоит:

if x == None:

это медленно, бессмысленно и вообще плохой тон.

Беглый обзор “внутренностей” Python 12

Page 30: Беглый обзор "внутренностей" Python

None

None - особый объектОн один на каждый инстанс интерпретатора. Совсем один.Поэтому для него is и == всегда эквивалентны.Вот так вот делать не стоит:

if x == None:

это медленно, бессмысленно и вообще плохой тон.

Беглый обзор “внутренностей” Python 12

Page 31: Беглый обзор "внутренностей" Python

intint - тип “малых” целых чисел

В Python целые - неизменяемый типПроверим как на них работает is:

>>> int("100") is int("100")True>>> int("1000") is int("1000")False

Как это объяснить? Оказывается, интерпретатор “кеширует”объекты int со значениями от -5 до 256, для других значенийсоздаются самостоятельные объекты.Поэтому список intов размером до байта будет иметь overhead в 8байт на элемент (указатель), а больших intов - до 32 байт наэлемент (указатель + объект).

Беглый обзор “внутренностей” Python 13

Page 32: Беглый обзор "внутренностей" Python

intint - тип “малых” целых чиселВ Python целые - неизменяемый тип

Проверим как на них работает is:

>>> int("100") is int("100")True>>> int("1000") is int("1000")False

Как это объяснить? Оказывается, интерпретатор “кеширует”объекты int со значениями от -5 до 256, для других значенийсоздаются самостоятельные объекты.Поэтому список intов размером до байта будет иметь overhead в 8байт на элемент (указатель), а больших intов - до 32 байт наэлемент (указатель + объект).

Беглый обзор “внутренностей” Python 13

Page 33: Беглый обзор "внутренностей" Python

intint - тип “малых” целых чиселВ Python целые - неизменяемый типПроверим как на них работает is:

>>> int("100") is int("100")True>>> int("1000") is int("1000")False

Как это объяснить? Оказывается, интерпретатор “кеширует”объекты int со значениями от -5 до 256, для других значенийсоздаются самостоятельные объекты.Поэтому список intов размером до байта будет иметь overhead в 8байт на элемент (указатель), а больших intов - до 32 байт наэлемент (указатель + объект).

Беглый обзор “внутренностей” Python 13

Page 34: Беглый обзор "внутренностей" Python

intint - тип “малых” целых чиселВ Python целые - неизменяемый типПроверим как на них работает is:

>>> int("100") is int("100")True>>> int("1000") is int("1000")False

Как это объяснить? Оказывается, интерпретатор “кеширует”объекты int со значениями от -5 до 256, для других значенийсоздаются самостоятельные объекты.

Поэтому список intов размером до байта будет иметь overhead в 8байт на элемент (указатель), а больших intов - до 32 байт наэлемент (указатель + объект).

Беглый обзор “внутренностей” Python 13

Page 35: Беглый обзор "внутренностей" Python

intint - тип “малых” целых чиселВ Python целые - неизменяемый типПроверим как на них работает is:

>>> int("100") is int("100")True>>> int("1000") is int("1000")False

Как это объяснить? Оказывается, интерпретатор “кеширует”объекты int со значениями от -5 до 256, для других значенийсоздаются самостоятельные объекты.Поэтому список intов размером до байта будет иметь overhead в 8байт на элемент (указатель), а больших intов - до 32 байт наэлемент (указатель + объект).

Беглый обзор “внутренностей” Python 13

Page 36: Беглый обзор "внутренностей" Python

int

Но загадки на этом не заканчиваются:

>>> (1000 is 1000, 1000+0 is 1000+0)(True, False)

Почему так - немного дальше.

Беглый обзор “внутренностей” Python 14

Page 37: Беглый обзор "внутренностей" Python

int

Но загадки на этом не заканчиваются:

>>> (1000 is 1000, 1000+0 is 1000+0)(True, False)

Почему так - немного дальше.

Беглый обзор “внутренностей” Python 14

Page 38: Беглый обзор "внутренностей" Python

string

Строки, как и целые, в Python неизменяемы

Однако sharing объектов их затрагивает куда сильнееИнтерпретатор поддерживает dict так называемых internedстрок, для каждой из которых гарантированно существует ровноодин объектВсе идентификаторы (имена переменных, модулей, методов),автоматически туда помещаютсяОператор == для interned строк выраждается в is (сравнениеуказателей)Помимо этого, по аналогии с int со значениями [−5, 256]разделяются объекты пустой и всех возможных однобуквенныхстрок

Беглый обзор “внутренностей” Python 15

Page 39: Беглый обзор "внутренностей" Python

string

Строки, как и целые, в Python неизменяемыОднако sharing объектов их затрагивает куда сильнее

Интерпретатор поддерживает dict так называемых internedстрок, для каждой из которых гарантированно существует ровноодин объектВсе идентификаторы (имена переменных, модулей, методов),автоматически туда помещаютсяОператор == для interned строк выраждается в is (сравнениеуказателей)Помимо этого, по аналогии с int со значениями [−5, 256]разделяются объекты пустой и всех возможных однобуквенныхстрок

Беглый обзор “внутренностей” Python 15

Page 40: Беглый обзор "внутренностей" Python

string

Строки, как и целые, в Python неизменяемыОднако sharing объектов их затрагивает куда сильнееИнтерпретатор поддерживает dict так называемых internedстрок, для каждой из которых гарантированно существует ровноодин объект

Все идентификаторы (имена переменных, модулей, методов),автоматически туда помещаютсяОператор == для interned строк выраждается в is (сравнениеуказателей)Помимо этого, по аналогии с int со значениями [−5, 256]разделяются объекты пустой и всех возможных однобуквенныхстрок

Беглый обзор “внутренностей” Python 15

Page 41: Беглый обзор "внутренностей" Python

string

Строки, как и целые, в Python неизменяемыОднако sharing объектов их затрагивает куда сильнееИнтерпретатор поддерживает dict так называемых internedстрок, для каждой из которых гарантированно существует ровноодин объектВсе идентификаторы (имена переменных, модулей, методов),автоматически туда помещаются

Оператор == для interned строк выраждается в is (сравнениеуказателей)Помимо этого, по аналогии с int со значениями [−5, 256]разделяются объекты пустой и всех возможных однобуквенныхстрок

Беглый обзор “внутренностей” Python 15

Page 42: Беглый обзор "внутренностей" Python

string

Строки, как и целые, в Python неизменяемыОднако sharing объектов их затрагивает куда сильнееИнтерпретатор поддерживает dict так называемых internedстрок, для каждой из которых гарантированно существует ровноодин объектВсе идентификаторы (имена переменных, модулей, методов),автоматически туда помещаютсяОператор == для interned строк выраждается в is (сравнениеуказателей)

Помимо этого, по аналогии с int со значениями [−5, 256]разделяются объекты пустой и всех возможных однобуквенныхстрок

Беглый обзор “внутренностей” Python 15

Page 43: Беглый обзор "внутренностей" Python

string

Строки, как и целые, в Python неизменяемыОднако sharing объектов их затрагивает куда сильнееИнтерпретатор поддерживает dict так называемых internedстрок, для каждой из которых гарантированно существует ровноодин объектВсе идентификаторы (имена переменных, модулей, методов),автоматически туда помещаютсяОператор == для interned строк выраждается в is (сравнениеуказателей)Помимо этого, по аналогии с int со значениями [−5, 256]разделяются объекты пустой и всех возможных однобуквенныхстрок

Беглый обзор “внутренностей” Python 15

Page 44: Беглый обзор "внутренностей" Python

Краткий вывод

Не используйте is для чего-то кроме None

Unless you know what you’re doing

Беглый обзор “внутренностей” Python 16

Page 45: Беглый обзор "внутренностей" Python

Краткий вывод

Не используйте is для чего-то кроме None

Unless you know what you’re doing

Беглый обзор “внутренностей” Python 16

Page 46: Беглый обзор "внутренностей" Python

Байткод

Беглый обзор “внутренностей” Python 17

Page 47: Беглый обзор "внутренностей" Python

Виртуальная машина

“Железный” процессор не может напрямую выполнять код на C

Его сначала нужно “разжевать” до очень простых операций,работающих с адресами и регистрамиКод на Python также не годится для непосредственногоисполненияПоэтому скрипт при загрузке транслируется в байткодвиртуальной машиныВиртуальная машина (VM) - это подпрограмма интерпретатора,испоняющая байткод.Но кроме отсутствия “железного” воплощения, концептуальныхразличий с процессором нет.

Беглый обзор “внутренностей” Python 18

Page 48: Беглый обзор "внутренностей" Python

Виртуальная машина

“Железный” процессор не может напрямую выполнять код на CЕго сначала нужно “разжевать” до очень простых операций,работающих с адресами и регистрами

Код на Python также не годится для непосредственногоисполненияПоэтому скрипт при загрузке транслируется в байткодвиртуальной машиныВиртуальная машина (VM) - это подпрограмма интерпретатора,испоняющая байткод.Но кроме отсутствия “железного” воплощения, концептуальныхразличий с процессором нет.

Беглый обзор “внутренностей” Python 18

Page 49: Беглый обзор "внутренностей" Python

Виртуальная машина

“Железный” процессор не может напрямую выполнять код на CЕго сначала нужно “разжевать” до очень простых операций,работающих с адресами и регистрамиКод на Python также не годится для непосредственногоисполнения

Поэтому скрипт при загрузке транслируется в байткодвиртуальной машиныВиртуальная машина (VM) - это подпрограмма интерпретатора,испоняющая байткод.Но кроме отсутствия “железного” воплощения, концептуальныхразличий с процессором нет.

Беглый обзор “внутренностей” Python 18

Page 50: Беглый обзор "внутренностей" Python

Виртуальная машина

“Железный” процессор не может напрямую выполнять код на CЕго сначала нужно “разжевать” до очень простых операций,работающих с адресами и регистрамиКод на Python также не годится для непосредственногоисполненияПоэтому скрипт при загрузке транслируется в байткодвиртуальной машины

Виртуальная машина (VM) - это подпрограмма интерпретатора,испоняющая байткод.Но кроме отсутствия “железного” воплощения, концептуальныхразличий с процессором нет.

Беглый обзор “внутренностей” Python 18

Page 51: Беглый обзор "внутренностей" Python

Виртуальная машина

“Железный” процессор не может напрямую выполнять код на CЕго сначала нужно “разжевать” до очень простых операций,работающих с адресами и регистрамиКод на Python также не годится для непосредственногоисполненияПоэтому скрипт при загрузке транслируется в байткодвиртуальной машиныВиртуальная машина (VM) - это подпрограмма интерпретатора,испоняющая байткод.

Но кроме отсутствия “железного” воплощения, концептуальныхразличий с процессором нет.

Беглый обзор “внутренностей” Python 18

Page 52: Беглый обзор "внутренностей" Python

Виртуальная машина

“Железный” процессор не может напрямую выполнять код на CЕго сначала нужно “разжевать” до очень простых операций,работающих с адресами и регистрамиКод на Python также не годится для непосредственногоисполненияПоэтому скрипт при загрузке транслируется в байткодвиртуальной машиныВиртуальная машина (VM) - это подпрограмма интерпретатора,испоняющая байткод.Но кроме отсутствия “железного” воплощения, концептуальныхразличий с процессором нет.

Беглый обзор “внутренностей” Python 18

Page 53: Беглый обзор "внутренностей" Python

Байткод

Команды CPython VM кодируются одним байтом

Каждая из них может иметь опциональный 16-битный аргументКонцептуально VM является стековой машиной (уместныаналогии с обратной польской записью и языком Forth) -значения кладутся на value stack (не путать с call stack), операцииих снимают с вершины и кладут результат обратно.При помощи модуля dis можно посмотреть на байткод “живых”функций

Беглый обзор “внутренностей” Python 19

Page 54: Беглый обзор "внутренностей" Python

Байткод

Команды CPython VM кодируются одним байтомКаждая из них может иметь опциональный 16-битный аргумент

Концептуально VM является стековой машиной (уместныаналогии с обратной польской записью и языком Forth) -значения кладутся на value stack (не путать с call stack), операцииих снимают с вершины и кладут результат обратно.При помощи модуля dis можно посмотреть на байткод “живых”функций

Беглый обзор “внутренностей” Python 19

Page 55: Беглый обзор "внутренностей" Python

Байткод

Команды CPython VM кодируются одним байтомКаждая из них может иметь опциональный 16-битный аргументКонцептуально VM является стековой машиной (уместныаналогии с обратной польской записью и языком Forth) -значения кладутся на value stack (не путать с call stack), операцииих снимают с вершины и кладут результат обратно.

При помощи модуля dis можно посмотреть на байткод “живых”функций

Беглый обзор “внутренностей” Python 19

Page 56: Беглый обзор "внутренностей" Python

Байткод

Команды CPython VM кодируются одним байтомКаждая из них может иметь опциональный 16-битный аргументКонцептуально VM является стековой машиной (уместныаналогии с обратной польской записью и языком Forth) -значения кладутся на value stack (не путать с call stack), операцииих снимают с вершины и кладут результат обратно.При помощи модуля dis можно посмотреть на байткод “живых”функций

Беглый обзор “внутренностей” Python 19

Page 57: Беглый обзор "внутренностей" Python

def f():a = 1b = 2c = 3return a + b * c

2 0 LOAD_CONST 1 (1)3 STORE_FAST 0 (a)

3 6 LOAD_CONST 2 (2)9 STORE_FAST 1 (b)

4 12 LOAD_CONST 3 (3)15 STORE_FAST 2 (c)

5 18 LOAD_FAST 0 (a)21 LOAD_FAST 1 (b)24 LOAD_FAST 2 (c)27 BINARY_MULTIPLY28 BINARY_ADD29 RETURN_VALUE

Беглый обзор “внутренностей” Python 20

Page 58: Беглый обзор "внутренностей" Python

Константы

def f(): return (1,"abc", 3.0)

>>> dis.dis(f)2 0 LOAD_CONST 4 ((1, ’abc’, 3.0))

3 RETURN_VALUE

>>> f.__code__.co_consts(None, 1, ’abc’, 3.0, (1, ’abc’, 3.0))

Беглый обзор “внутренностей” Python 21

Page 59: Беглый обзор "внутренностей" Python

Константы

def f(): return (1,"abc", 3.0)

>>> dis.dis(f)2 0 LOAD_CONST 4 ((1, ’abc’, 3.0))

3 RETURN_VALUE

>>> f.__code__.co_consts(None, 1, ’abc’, 3.0, (1, ’abc’, 3.0))

Беглый обзор “внутренностей” Python 21

Page 60: Беглый обзор "внутренностей" Python

Константы

def f(): return (1,"abc", 3.0)

>>> dis.dis(f)2 0 LOAD_CONST 4 ((1, ’abc’, 3.0))

3 RETURN_VALUE

>>> f.__code__.co_consts(None, 1, ’abc’, 3.0, (1, ’abc’, 3.0))

Беглый обзор “внутренностей” Python 21

Page 61: Беглый обзор "внутренностей" Python

Code object

Как мы видим, байткод это не просто строка байт, так как16-битных целых недостаточно, чтобы кодировать любыеPython-объекты

Однако их достаточно, чтобы кодировать смещения. Например, всписок констант co_consts

Наряду с другой метаинформацией (количество локальныхпеременных, количество параметров, глубина стека) байткодформирует code object

Именно code object являет собой единицу существованиякомпилированного кода в PythonОни же сериализуются в .pyc файлы

Беглый обзор “внутренностей” Python 22

Page 62: Беглый обзор "внутренностей" Python

Code object

Как мы видим, байткод это не просто строка байт, так как16-битных целых недостаточно, чтобы кодировать любыеPython-объектыОднако их достаточно, чтобы кодировать смещения. Например, всписок констант co_consts

Наряду с другой метаинформацией (количество локальныхпеременных, количество параметров, глубина стека) байткодформирует code object

Именно code object являет собой единицу существованиякомпилированного кода в PythonОни же сериализуются в .pyc файлы

Беглый обзор “внутренностей” Python 22

Page 63: Беглый обзор "внутренностей" Python

Code object

Как мы видим, байткод это не просто строка байт, так как16-битных целых недостаточно, чтобы кодировать любыеPython-объектыОднако их достаточно, чтобы кодировать смещения. Например, всписок констант co_consts

Наряду с другой метаинформацией (количество локальныхпеременных, количество параметров, глубина стека) байткодформирует code object

Именно code object являет собой единицу существованиякомпилированного кода в PythonОни же сериализуются в .pyc файлы

Беглый обзор “внутренностей” Python 22

Page 64: Беглый обзор "внутренностей" Python

Code object

Как мы видим, байткод это не просто строка байт, так как16-битных целых недостаточно, чтобы кодировать любыеPython-объектыОднако их достаточно, чтобы кодировать смещения. Например, всписок констант co_consts

Наряду с другой метаинформацией (количество локальныхпеременных, количество параметров, глубина стека) байткодформирует code object

Именно code object являет собой единицу существованиякомпилированного кода в Python

Они же сериализуются в .pyc файлы

Беглый обзор “внутренностей” Python 22

Page 65: Беглый обзор "внутренностей" Python

Code object

Как мы видим, байткод это не просто строка байт, так как16-битных целых недостаточно, чтобы кодировать любыеPython-объектыОднако их достаточно, чтобы кодировать смещения. Например, всписок констант co_consts

Наряду с другой метаинформацией (количество локальныхпеременных, количество параметров, глубина стека) байткодформирует code object

Именно code object являет собой единицу существованиякомпилированного кода в PythonОни же сериализуются в .pyc файлы

Беглый обзор “внутренностей” Python 22

Page 66: Беглый обзор "внутренностей" Python

Code objectcode object являются неизменяемыми

В “нормальном” коде они строятся единожды - при загрузкемодуляЭто такой же объект как и все:

def f():def g(): passreturn g

2 0 LOAD_CONST 1 (<code object f ...>)3 MAKE_FUNCTION 06 STORE_FAST 0 (f)

3 9 LOAD_GLOBAL 0 (g)12 RETURN_VALUE

Беглый обзор “внутренностей” Python 23

Page 67: Беглый обзор "внутренностей" Python

Code objectcode object являются неизменяемымиВ “нормальном” коде они строятся единожды - при загрузкемодуля

Это такой же объект как и все:

def f():def g(): passreturn g

2 0 LOAD_CONST 1 (<code object f ...>)3 MAKE_FUNCTION 06 STORE_FAST 0 (f)

3 9 LOAD_GLOBAL 0 (g)12 RETURN_VALUE

Беглый обзор “внутренностей” Python 23

Page 68: Беглый обзор "внутренностей" Python

Code objectcode object являются неизменяемымиВ “нормальном” коде они строятся единожды - при загрузкемодуляЭто такой же объект как и все:

def f():def g(): passreturn g

2 0 LOAD_CONST 1 (<code object f ...>)3 MAKE_FUNCTION 06 STORE_FAST 0 (f)

3 9 LOAD_GLOBAL 0 (g)12 RETURN_VALUE

Беглый обзор “внутренностей” Python 23

Page 69: Беглый обзор "внутренностей" Python

Компиляция

Процесс преобразования исходного кода модуля в наборcode object называется компиляцией

Однако компилятор у Python очень рудиментарный - фактически1-в-1 отображение конструкций в байткодОптимизаций уровня байткода почти нетuncompyle, open source декомпилятор Python, способенвосстановить исходный код по .pyc файлу почти всегда, потерявпри этом разве что комментарииТак как компилятор неоптимизирующий, ему почти всегда можнопомочь (если надо)

Беглый обзор “внутренностей” Python 24

Page 70: Беглый обзор "внутренностей" Python

Компиляция

Процесс преобразования исходного кода модуля в наборcode object называется компиляциейОднако компилятор у Python очень рудиментарный - фактически1-в-1 отображение конструкций в байткод

Оптимизаций уровня байткода почти нетuncompyle, open source декомпилятор Python, способенвосстановить исходный код по .pyc файлу почти всегда, потерявпри этом разве что комментарииТак как компилятор неоптимизирующий, ему почти всегда можнопомочь (если надо)

Беглый обзор “внутренностей” Python 24

Page 71: Беглый обзор "внутренностей" Python

Компиляция

Процесс преобразования исходного кода модуля в наборcode object называется компиляциейОднако компилятор у Python очень рудиментарный - фактически1-в-1 отображение конструкций в байткодОптимизаций уровня байткода почти нет

uncompyle, open source декомпилятор Python, способенвосстановить исходный код по .pyc файлу почти всегда, потерявпри этом разве что комментарииТак как компилятор неоптимизирующий, ему почти всегда можнопомочь (если надо)

Беглый обзор “внутренностей” Python 24

Page 72: Беглый обзор "внутренностей" Python

Компиляция

Процесс преобразования исходного кода модуля в наборcode object называется компиляциейОднако компилятор у Python очень рудиментарный - фактически1-в-1 отображение конструкций в байткодОптимизаций уровня байткода почти нетuncompyle, open source декомпилятор Python, способенвосстановить исходный код по .pyc файлу почти всегда, потерявпри этом разве что комментарии

Так как компилятор неоптимизирующий, ему почти всегда можнопомочь (если надо)

Беглый обзор “внутренностей” Python 24

Page 73: Беглый обзор "внутренностей" Python

Компиляция

Процесс преобразования исходного кода модуля в наборcode object называется компиляциейОднако компилятор у Python очень рудиментарный - фактически1-в-1 отображение конструкций в байткодОптимизаций уровня байткода почти нетuncompyle, open source декомпилятор Python, способенвосстановить исходный код по .pyc файлу почти всегда, потерявпри этом разве что комментарииТак как компилятор неоптимизирующий, ему почти всегда можнопомочь (если надо)

Беглый обзор “внутренностей” Python 24

Page 74: Беглый обзор "внутренностей" Python

Компиляция

def f():l = []for i in xrange(10000):

l.append(i)

>>> timeit.timeit("""....""")0.09371685981750488

>>> dis.dis(f) (... оставлено только тело цикла ...)4 25 LOAD_FAST 0 (l)

28 LOAD_ATTR 1 (append)31 LOAD_FAST 1 (i)34 CALL_FUNCTION 1

Беглый обзор “внутренностей” Python 25

Page 75: Беглый обзор "внутренностей" Python

Loop hoisting

LOAD_ATTR по идее выполняется небыстро - это поиск строки сименем метода в дикте (хеш-таблице). Строка interned, но всеравно это долго.

Логично не выполнять эту операцию в теле цикла, а сделать ееединожды до начала выполнения.Эта оптимизация известна как loop hoisting, но рудиментарныйкомпилятор Python ее не делает.Поможем ему!

Беглый обзор “внутренностей” Python 26

Page 76: Беглый обзор "внутренностей" Python

Loop hoisting

LOAD_ATTR по идее выполняется небыстро - это поиск строки сименем метода в дикте (хеш-таблице). Строка interned, но всеравно это долго.Логично не выполнять эту операцию в теле цикла, а сделать ееединожды до начала выполнения.

Эта оптимизация известна как loop hoisting, но рудиментарныйкомпилятор Python ее не делает.Поможем ему!

Беглый обзор “внутренностей” Python 26

Page 77: Беглый обзор "внутренностей" Python

Loop hoisting

LOAD_ATTR по идее выполняется небыстро - это поиск строки сименем метода в дикте (хеш-таблице). Строка interned, но всеравно это долго.Логично не выполнять эту операцию в теле цикла, а сделать ееединожды до начала выполнения.Эта оптимизация известна как loop hoisting, но рудиментарныйкомпилятор Python ее не делает.

Поможем ему!

Беглый обзор “внутренностей” Python 26

Page 78: Беглый обзор "внутренностей" Python

Loop hoisting

LOAD_ATTR по идее выполняется небыстро - это поиск строки сименем метода в дикте (хеш-таблице). Строка interned, но всеравно это долго.Логично не выполнять эту операцию в теле цикла, а сделать ееединожды до начала выполнения.Эта оптимизация известна как loop hoisting, но рудиментарныйкомпилятор Python ее не делает.Поможем ему!

Беглый обзор “внутренностей” Python 26

Page 79: Беглый обзор "внутренностей" Python

Loop hoisting

def f():l = []la = l.appendfor i in xrange(10000):

la(i)

>>> timeit.timeit("""....""")0.08451047520987543

>>> dis.dis(f) (... оставлено только тело цикла ...)5 34 LOAD_FAST 1 (la)

37 LOAD_FAST 2 (i)40 CALL_FUNCTION 1

До оптимизации было 0.09371685981750488. Разница - 10%.

Беглый обзор “внутренностей” Python 27

Page 80: Беглый обзор "внутренностей" Python

LIST_APPEND

Добавление к списку - частая операция, и потому в CPython VMесть особый опкод LIST_APPEND

Как показывает изучение исходников компилятора, используетсяэтот опкод только для компиляции list comprehensions:def f():

return [x for x in xrange(10000)]

>>> timeit.timeit("""....""")0.08152854398842842

>>> dis.dis(f) (... оставлено только тело цикла ...)16 STORE_FAST 0 (x)19 LOAD_FAST 0 (x)22 LIST_APPEND 2

Беглый обзор “внутренностей” Python 28

Page 81: Беглый обзор "внутренностей" Python

LIST_APPEND

Добавление к списку - частая операция, и потому в CPython VMесть особый опкод LIST_APPEND

Как показывает изучение исходников компилятора, используетсяэтот опкод только для компиляции list comprehensions:def f():

return [x for x in xrange(10000)]

>>> timeit.timeit("""....""")0.08152854398842842

>>> dis.dis(f) (... оставлено только тело цикла ...)16 STORE_FAST 0 (x)19 LOAD_FAST 0 (x)22 LIST_APPEND 2

Беглый обзор “внутренностей” Python 28

Page 82: Беглый обзор "внутренностей" Python

Неймспейсы

Беглый обзор “внутренностей” Python 29

Page 83: Беглый обзор "внутренностей" Python

Дикты и строки

Многие знакомые с семантикой Python люди шутят, что Гвидо ванРоссум написал dict (открытую хеш-таблицу) и string(неизменяемые строки), после чего решил больше ничего неписать

Действительно, объекты, модули и неймспейсы - все это обычныедикты cо строковыми ключамиГлобальное пространство имен модуля, следовательно, тоже дикт,а обращение к переменной - это lookup в дикте.Всегда ли это так?

Беглый обзор “внутренностей” Python 30

Page 84: Беглый обзор "внутренностей" Python

Дикты и строки

Многие знакомые с семантикой Python люди шутят, что Гвидо ванРоссум написал dict (открытую хеш-таблицу) и string(неизменяемые строки), после чего решил больше ничего неписатьДействительно, объекты, модули и неймспейсы - все это обычныедикты cо строковыми ключами

Глобальное пространство имен модуля, следовательно, тоже дикт,а обращение к переменной - это lookup в дикте.Всегда ли это так?

Беглый обзор “внутренностей” Python 30

Page 85: Беглый обзор "внутренностей" Python

Дикты и строки

Многие знакомые с семантикой Python люди шутят, что Гвидо ванРоссум написал dict (открытую хеш-таблицу) и string(неизменяемые строки), после чего решил больше ничего неписатьДействительно, объекты, модули и неймспейсы - все это обычныедикты cо строковыми ключамиГлобальное пространство имен модуля, следовательно, тоже дикт,а обращение к переменной - это lookup в дикте.

Всегда ли это так?

Беглый обзор “внутренностей” Python 30

Page 86: Беглый обзор "внутренностей" Python

Дикты и строки

Многие знакомые с семантикой Python люди шутят, что Гвидо ванРоссум написал dict (открытую хеш-таблицу) и string(неизменяемые строки), после чего решил больше ничего неписатьДействительно, объекты, модули и неймспейсы - все это обычныедикты cо строковыми ключамиГлобальное пространство имен модуля, следовательно, тоже дикт,а обращение к переменной - это lookup в дикте.Всегда ли это так?

Беглый обзор “внутренностей” Python 30

Page 87: Беглый обзор "внутренностей" Python

Дикты и строки

def f():a = 3return a + b

2 0 LOAD_CONST 1 (1)3 STORE_FAST 0 (a)

3 6 LOAD_FAST 0 (a)9 LOAD_GLOBAL 0 (b)

12 BINARY_ADD13 RETURN_VALUE

Беглый обзор “внутренностей” Python 31

Page 88: Беглый обзор "внутренностей" Python

LOAD_FAST и LOAD_GLOBAL

3 6 LOAD_FAST 0 (a)9 LOAD_GLOBAL 0 (b)

Для имен a и b компилятор использовал разные опкоды. Почему?

Оказывается, на этапе компиляции в code object собираются всеимена локальных переменных (то есть присваиваемые в этомблоке кода и не помеченные явно при помощи global), изаносятся в список co_locals.Впоследствии для каждого фрейма стека создается массивлокальных переменных, и обращение к ним происходит по ихиндексу в co_locals. Этот индекс неизменен и “зашит” в байткод.

Беглый обзор “внутренностей” Python 32

Page 89: Беглый обзор "внутренностей" Python

LOAD_FAST и LOAD_GLOBAL

3 6 LOAD_FAST 0 (a)9 LOAD_GLOBAL 0 (b)

Для имен a и b компилятор использовал разные опкоды. Почему?Оказывается, на этапе компиляции в code object собираются всеимена локальных переменных (то есть присваиваемые в этомблоке кода и не помеченные явно при помощи global), изаносятся в список co_locals.

Впоследствии для каждого фрейма стека создается массивлокальных переменных, и обращение к ним происходит по ихиндексу в co_locals. Этот индекс неизменен и “зашит” в байткод.

Беглый обзор “внутренностей” Python 32

Page 90: Беглый обзор "внутренностей" Python

LOAD_FAST и LOAD_GLOBAL

3 6 LOAD_FAST 0 (a)9 LOAD_GLOBAL 0 (b)

Для имен a и b компилятор использовал разные опкоды. Почему?Оказывается, на этапе компиляции в code object собираются всеимена локальных переменных (то есть присваиваемые в этомблоке кода и не помеченные явно при помощи global), изаносятся в список co_locals.Впоследствии для каждого фрейма стека создается массивлокальных переменных, и обращение к ним происходит по ихиндексу в co_locals. Этот индекс неизменен и “зашит” в байткод.

Беглый обзор “внутренностей” Python 32

Page 91: Беглый обзор "внутренностей" Python

LOAD_FAST и LOAD_GLOBAL

LOAD_FAST, как нетрудно догадаться, просто берет значение поиндексу из массива

LOAD_GLOBAL же вынужден брать строку с именем из co_consts,после чего искать по этому ключу в дикте неймспейсаОбе операции выполняются с ожидаемой стоимостью O(1), но умассива константа явно лучшеПоэтому закешировать что-то в локальную переменную не самаяплохая идея в плане производительности

Беглый обзор “внутренностей” Python 33

Page 92: Беглый обзор "внутренностей" Python

LOAD_FAST и LOAD_GLOBAL

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

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

Беглый обзор “внутренностей” Python 33

Page 93: Беглый обзор "внутренностей" Python

LOAD_FAST и LOAD_GLOBAL

LOAD_FAST, как нетрудно догадаться, просто берет значение поиндексу из массиваLOAD_GLOBAL же вынужден брать строку с именем из co_consts,после чего искать по этому ключу в дикте неймспейсаОбе операции выполняются с ожидаемой стоимостью O(1), но умассива константа явно лучше

Поэтому закешировать что-то в локальную переменную не самаяплохая идея в плане производительности

Беглый обзор “внутренностей” Python 33

Page 94: Беглый обзор "внутренностей" Python

LOAD_FAST и LOAD_GLOBAL

LOAD_FAST, как нетрудно догадаться, просто берет значение поиндексу из массиваLOAD_GLOBAL же вынужден брать строку с именем из co_consts,после чего искать по этому ключу в дикте неймспейсаОбе операции выполняются с ожидаемой стоимостью O(1), но умассива константа явно лучшеПоэтому закешировать что-то в локальную переменную не самаяплохая идея в плане производительности

Беглый обзор “внутренностей” Python 33

Page 95: Беглый обзор "внутренностей" Python

Lexical scoping

Глобальный и локальный неймспейсы достаточно очевидны самипо себе

Однако Python позволяет делать вот так:

def f():a = 1def g(): return areturn g

>>> t = f()>>> t()1

Как возвращенной функции удается вернуть значение изразрушенного фрейма?

Беглый обзор “внутренностей” Python 34

Page 96: Беглый обзор "внутренностей" Python

Lexical scoping

Глобальный и локальный неймспейсы достаточно очевидны самипо себеОднако Python позволяет делать вот так:

def f():a = 1def g(): return areturn g

>>> t = f()>>> t()1

Как возвращенной функции удается вернуть значение изразрушенного фрейма?

Беглый обзор “внутренностей” Python 34

Page 97: Беглый обзор "внутренностей" Python

Lexical scoping

Глобальный и локальный неймспейсы достаточно очевидны самипо себеОднако Python позволяет делать вот так:

def f():a = 1def g(): return areturn g

>>> t = f()>>> t()1

Как возвращенной функции удается вернуть значение изразрушенного фрейма?

Беглый обзор “внутренностей” Python 34

Page 98: Беглый обзор "внутренностей" Python

Lexical scopingОказывается, такая ситуация детектируется при компиляции ирешается при помощи создания cell object (в функциональныхязыках подобные объекты называют замыканиями или closures):

2 0 LOAD_CONST 1 (1)3 STORE_DEREF 0 (a)

3 6 LOAD_CLOSURE 0 (a)9 BUILD_TUPLE 1

12 LOAD_CONST 2 (<code object ...>)15 MAKE_CLOSURE 018 STORE_FAST 0 (g)

4 21 LOAD_FAST 0 (g)24 RETURN_VALUE

cell object - это код функции вместе со значениями “внешних”(свободных, free) переменных

Беглый обзор “внутренностей” Python 35

Page 99: Беглый обзор "внутренностей" Python

Lexical scopingОказывается, такая ситуация детектируется при компиляции ирешается при помощи создания cell object (в функциональныхязыках подобные объекты называют замыканиями или closures):

2 0 LOAD_CONST 1 (1)3 STORE_DEREF 0 (a)

3 6 LOAD_CLOSURE 0 (a)9 BUILD_TUPLE 1

12 LOAD_CONST 2 (<code object ...>)15 MAKE_CLOSURE 018 STORE_FAST 0 (g)

4 21 LOAD_FAST 0 (g)24 RETURN_VALUE

cell object - это код функции вместе со значениями “внешних”(свободных, free) переменных

Беглый обзор “внутренностей” Python 35

Page 100: Беглый обзор "внутренностей" Python

Lexical scoping

cell object по времени жизни не привязан к фрейму, в которомон создан, и собирается сборщиком мусора только тогда, когдастанет недостижим.

Это “взрослая” реализация лексической области видимостиОднако, к сожалению, она неполна:

def f():a = 1if True: a = 2; print aprint a

этот код выведет 2 2. Аналогичный код на C++, или, скажем,Lua, выдаст 2 1

Это источник трудноуловимых багов

Беглый обзор “внутренностей” Python 36

Page 101: Беглый обзор "внутренностей" Python

Lexical scoping

cell object по времени жизни не привязан к фрейму, в которомон создан, и собирается сборщиком мусора только тогда, когдастанет недостижим.Это “взрослая” реализация лексической области видимости

Однако, к сожалению, она неполна:

def f():a = 1if True: a = 2; print aprint a

этот код выведет 2 2. Аналогичный код на C++, или, скажем,Lua, выдаст 2 1

Это источник трудноуловимых багов

Беглый обзор “внутренностей” Python 36

Page 102: Беглый обзор "внутренностей" Python

Lexical scoping

cell object по времени жизни не привязан к фрейму, в которомон создан, и собирается сборщиком мусора только тогда, когдастанет недостижим.Это “взрослая” реализация лексической области видимостиОднако, к сожалению, она неполна:

def f():a = 1if True: a = 2; print aprint a

этот код выведет 2 2. Аналогичный код на C++, или, скажем,Lua, выдаст 2 1

Это источник трудноуловимых багов

Беглый обзор “внутренностей” Python 36

Page 103: Беглый обзор "внутренностей" Python

Lexical scoping

cell object по времени жизни не привязан к фрейму, в которомон создан, и собирается сборщиком мусора только тогда, когдастанет недостижим.Это “взрослая” реализация лексической области видимостиОднако, к сожалению, она неполна:

def f():a = 1if True: a = 2; print aprint a

этот код выведет 2 2. Аналогичный код на C++, или, скажем,Lua, выдаст 2 1

Это источник трудноуловимых багов

Беглый обзор “внутренностей” Python 36

Page 104: Беглый обзор "внутренностей" Python

Выстрелить в ногу!

Что выведет это код?

l = [lambda: x for x in "abcdefg"]for r in l: print r(),

Наверное a b c d e f g?Реальность жестока.Правильный ответ - g g g g g g g.

Беглый обзор “внутренностей” Python 37

Page 105: Беглый обзор "внутренностей" Python

Выстрелить в ногу!

Что выведет это код?

l = [lambda: x for x in "abcdefg"]for r in l: print r(),

Наверное a b c d e f g?

Реальность жестока.Правильный ответ - g g g g g g g.

Беглый обзор “внутренностей” Python 37

Page 106: Беглый обзор "внутренностей" Python

Выстрелить в ногу!

Что выведет это код?

l = [lambda: x for x in "abcdefg"]for r in l: print r(),

Наверное a b c d e f g?Реальность жестока.

Правильный ответ - g g g g g g g.

Беглый обзор “внутренностей” Python 37

Page 107: Беглый обзор "внутренностей" Python

Выстрелить в ногу!

Что выведет это код?

l = [lambda: x for x in "abcdefg"]for r in l: print r(),

Наверное a b c d e f g?Реальность жестока.Правильный ответ - g g g g g g g.

Беглый обзор “внутренностей” Python 37

Page 108: Беглый обзор "внутренностей" Python

Lexical scoping

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

Даже если это сделать - это с большой вероятностью приведет к“ломанию” имеющегося кодаПоэтому про данную особенность надо просто помнить, и несильно увлекаться функциональным программированием наPython ;)

Беглый обзор “внутренностей” Python 38

Page 109: Беглый обзор "внутренностей" Python

Lexical scoping

К сожалению, различие поведения областей видимости на макро-и микроуровнях настолько глубоко зашито в архитектуре языка,что поправить его практически нереальноДаже если это сделать - это с большой вероятностью приведет к“ломанию” имеющегося кода

Поэтому про данную особенность надо просто помнить, и несильно увлекаться функциональным программированием наPython ;)

Беглый обзор “внутренностей” Python 38

Page 110: Беглый обзор "внутренностей" Python

Lexical scoping

К сожалению, различие поведения областей видимости на макро-и микроуровнях настолько глубоко зашито в архитектуре языка,что поправить его практически нереальноДаже если это сделать - это с большой вероятностью приведет к“ломанию” имеющегося кодаПоэтому про данную особенность надо просто помнить, и несильно увлекаться функциональным программированием наPython ;)

Беглый обзор “внутренностей” Python 38

Page 111: Беглый обзор "внутренностей" Python

Заключение

Беглый обзор “внутренностей” Python 39

Page 112: Беглый обзор "внутренностей" Python

Заключение

К сожалению, регламент данного доклада не дает слишкомразогнаться. За бортом остаются многие интересные темы:

Global Interpreter Lock (GIL), или почему программы на Python нанескольких ядрах работают медленнее, чем на одномframe object и их список, или как greenlet умудряетсяэмулировать кооперативную многозадачность “срезанием” стекаООП в Python, или почему у object нельзя выставить атрибут, ау унаследованного от него пустого класса - можноГенераторы, или как “шаманство” с фреймами позволяетсоздавать видимость их (генераторов) наличия, но с серьезнымиограничениями

Беглый обзор “внутренностей” Python 40

Page 113: Беглый обзор "внутренностей" Python

Заключение

К сожалению, регламент данного доклада не дает слишкомразогнаться. За бортом остаются многие интересные темы:Global Interpreter Lock (GIL), или почему программы на Python нанескольких ядрах работают медленнее, чем на одном

frame object и их список, или как greenlet умудряетсяэмулировать кооперативную многозадачность “срезанием” стекаООП в Python, или почему у object нельзя выставить атрибут, ау унаследованного от него пустого класса - можноГенераторы, или как “шаманство” с фреймами позволяетсоздавать видимость их (генераторов) наличия, но с серьезнымиограничениями

Беглый обзор “внутренностей” Python 40

Page 114: Беглый обзор "внутренностей" Python

Заключение

К сожалению, регламент данного доклада не дает слишкомразогнаться. За бортом остаются многие интересные темы:Global Interpreter Lock (GIL), или почему программы на Python нанескольких ядрах работают медленнее, чем на одномframe object и их список, или как greenlet умудряетсяэмулировать кооперативную многозадачность “срезанием” стека

ООП в Python, или почему у object нельзя выставить атрибут, ау унаследованного от него пустого класса - можноГенераторы, или как “шаманство” с фреймами позволяетсоздавать видимость их (генераторов) наличия, но с серьезнымиограничениями

Беглый обзор “внутренностей” Python 40

Page 115: Беглый обзор "внутренностей" Python

Заключение

К сожалению, регламент данного доклада не дает слишкомразогнаться. За бортом остаются многие интересные темы:Global Interpreter Lock (GIL), или почему программы на Python нанескольких ядрах работают медленнее, чем на одномframe object и их список, или как greenlet умудряетсяэмулировать кооперативную многозадачность “срезанием” стекаООП в Python, или почему у object нельзя выставить атрибут, ау унаследованного от него пустого класса - можно

Генераторы, или как “шаманство” с фреймами позволяетсоздавать видимость их (генераторов) наличия, но с серьезнымиограничениями

Беглый обзор “внутренностей” Python 40

Page 116: Беглый обзор "внутренностей" Python

Заключение

К сожалению, регламент данного доклада не дает слишкомразогнаться. За бортом остаются многие интересные темы:Global Interpreter Lock (GIL), или почему программы на Python нанескольких ядрах работают медленнее, чем на одномframe object и их список, или как greenlet умудряетсяэмулировать кооперативную многозадачность “срезанием” стекаООП в Python, или почему у object нельзя выставить атрибут, ау унаследованного от него пустого класса - можноГенераторы, или как “шаманство” с фреймами позволяетсоздавать видимость их (генераторов) наличия, но с серьезнымиограничениями

Беглый обзор “внутренностей” Python 40

Page 117: Беглый обзор "внутренностей" Python

Заключение

Однако большой проблемы нет - это не сакральное знание

Все, что я вам сегодня рассказал, я не прочитал в интернете и наStackOverflow - я прочитал это в исходных кодах интерпретатораОни действительно неплохо структурированы и их довольнопросто читать, даже людям без соответствующего бэкграундаМне это помогло глубже понять как работает тот код, который япишу, что порой оказывалось очень полезным при профайлингекритичных местЭто как раз тот случай, когда вместо того, чтобы лезть наStackOverflow, полезнее и интереснее разобраться самому. Такчто дерзайте!

Беглый обзор “внутренностей” Python 41

Page 118: Беглый обзор "внутренностей" Python

Заключение

Однако большой проблемы нет - это не сакральное знаниеВсе, что я вам сегодня рассказал, я не прочитал в интернете и наStackOverflow - я прочитал это в исходных кодах интерпретатора

Они действительно неплохо структурированы и их довольнопросто читать, даже людям без соответствующего бэкграундаМне это помогло глубже понять как работает тот код, который япишу, что порой оказывалось очень полезным при профайлингекритичных местЭто как раз тот случай, когда вместо того, чтобы лезть наStackOverflow, полезнее и интереснее разобраться самому. Такчто дерзайте!

Беглый обзор “внутренностей” Python 41

Page 119: Беглый обзор "внутренностей" Python

Заключение

Однако большой проблемы нет - это не сакральное знаниеВсе, что я вам сегодня рассказал, я не прочитал в интернете и наStackOverflow - я прочитал это в исходных кодах интерпретатораОни действительно неплохо структурированы и их довольнопросто читать, даже людям без соответствующего бэкграунда

Мне это помогло глубже понять как работает тот код, который япишу, что порой оказывалось очень полезным при профайлингекритичных местЭто как раз тот случай, когда вместо того, чтобы лезть наStackOverflow, полезнее и интереснее разобраться самому. Такчто дерзайте!

Беглый обзор “внутренностей” Python 41

Page 120: Беглый обзор "внутренностей" Python

Заключение

Однако большой проблемы нет - это не сакральное знаниеВсе, что я вам сегодня рассказал, я не прочитал в интернете и наStackOverflow - я прочитал это в исходных кодах интерпретатораОни действительно неплохо структурированы и их довольнопросто читать, даже людям без соответствующего бэкграундаМне это помогло глубже понять как работает тот код, который япишу, что порой оказывалось очень полезным при профайлингекритичных мест

Это как раз тот случай, когда вместо того, чтобы лезть наStackOverflow, полезнее и интереснее разобраться самому. Такчто дерзайте!

Беглый обзор “внутренностей” Python 41

Page 121: Беглый обзор "внутренностей" Python

Заключение

Однако большой проблемы нет - это не сакральное знаниеВсе, что я вам сегодня рассказал, я не прочитал в интернете и наStackOverflow - я прочитал это в исходных кодах интерпретатораОни действительно неплохо структурированы и их довольнопросто читать, даже людям без соответствующего бэкграундаМне это помогло глубже понять как работает тот код, который япишу, что порой оказывалось очень полезным при профайлингекритичных местЭто как раз тот случай, когда вместо того, чтобы лезть наStackOverflow, полезнее и интереснее разобраться самому. Такчто дерзайте!

Беглый обзор “внутренностей” Python 41

Page 122: Беглый обзор "внутренностей" Python

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

Page 123: Беглый обзор "внутренностей" Python

Вопросы?