SlideShare una empresa de Scribd logo
1 de 123
Descargar para leer sin conexión
Беглый обзор “внутренностей” Python
Никита Лесников
Почему это может быть полезно?
Часто у программиста, использующего в работе Python, возникает
один из следующих вопросов:
какой из двух способов решения проблемы потребляет меньше
памяти?
Беглый обзор “внутренностей” Python 2
Почему это может быть полезно?
Часто у программиста, использующего в работе Python, возникает
один из следующих вопросов:
какой из двух способов решения проблемы потребляет меньше
памяти?
какой из двух способов работает быстрее?
Беглый обзор “внутренностей” Python 2
Почему это может быть полезно?
Часто у программиста, использующего в работе Python, возникает
один из следующих вопросов:
какой из двух способов решения проблемы потребляет меньше
памяти?
какой из двух способов работает быстрее?
как поведет себя определенная конструкция при изменении
runtime среды?
Беглый обзор “внутренностей” Python 2
Почему это может быть полезно?
Решаются они обычно одним из следующих способов:
можно спросить у коллег
Беглый обзор “внутренностей” Python 3
Почему это может быть полезно?
Решаются они обычно одним из следующих способов:
можно спросить у коллег
можно найти ответ на StackOverflow
Беглый обзор “внутренностей” Python 3
Почему это может быть полезно?
Решаются они обычно одним из следующих способов:
можно спросить у коллег
можно найти ответ на StackOverflow
можно замерить самому
Беглый обзор “внутренностей” Python 3
Почему это может быть полезно?
Однако понимание того, как работает интерпретатор на самых
нижних уровнях, позволяет обрести интуитивное понимание
нюансов работы многих конструкций языка.
Беглый обзор “внутренностей” Python 4
Почему это может быть полезно?
Однако понимание того, как работает интерпретатор на самых
нижних уровнях, позволяет обрести интуитивное понимание
нюансов работы многих конструкций языка.
Кроме того, в случае с Python абсолютное большинство
программистов обладает достаточной квалификацией, чтобы без
посредников найти ответ на свой вопрос в исходниках
интерпретатора.
Беглый обзор “внутренностей” Python 4
Почему это может быть полезно?
Знакомство с “внутренностями” полезно также потому, что Python
является open source проектом - кто знает, быть может именно вы
решите одну из наболевших проблем? ;)
Беглый обзор “внутренностей” Python 5
Почему это может быть полезно?
Знакомство с “внутренностями” полезно также потому, что Python
является open source проектом - кто знает, быть может именно вы
решите одну из наболевших проблем? ;)
Кратким изучением наиболее характерных особенностей
интерпретатора мы сейчас и займемся.
Беглый обзор “внутренностей” Python 5
CPython
Основная реализация Python на сегодняшний день
Беглый обзор “внутренностей” Python 6
CPython
Основная реализация Python на сегодняшний день
Написана на C (не С++), кроссплатформенна и довольно легко
переносима на отличные от официально поддерживаемых
платформы
Беглый обзор “внутренностей” Python 6
CPython
Основная реализация Python на сегодняшний день
Написана на C (не С++), кроссплатформенна и довольно легко
переносима на отличные от официально поддерживаемых
платформы
Код простой и понятный
Беглый обзор “внутренностей” Python 6
CPython
Основная реализация Python на сегодняшний день
Написана на C (не С++), кроссплатформенна и довольно легко
переносима на отличные от официально поддерживаемых
платформы
Код простой и понятный
Нет, серьезно, простой и понятный, даже для людей, не
интересующихся разработкой языков программирования ;)
Беглый обзор “внутренностей” Python 6
CPython
Есть еще PyPy, IronPython, Jython, Boo (хотя это не совсем
Python)
Беглый обзор “внутренностей” Python 7
CPython
Есть еще PyPy, IronPython, Jython, Boo (хотя это не совсем
Python)
Они по своему интересны, но с CPython “внутри” у них мало
общего
Беглый обзор “внутренностей” Python 7
CPython
Есть еще PyPy, IronPython, Jython, Boo (хотя это не совсем
Python)
Они по своему интересны, но с CPython “внутри” у них мало
общего
Поэтому хотя они и могут быть очень полезны на практике,
рассматривать их мы не будем
Беглый обзор “внутренностей” Python 7
Все - объект.
Беглый обзор “внутренностей” Python 8
Все - объект
В Python все является объектом
Беглый обзор “внутренностей” Python 9
Все - объект
В Python все является объектом
Ну то есть вообще все - от чисел до стакфреймов
Беглый обзор “внутренностей” Python 9
Все - объект
В Python все является объектом
Ну то есть вообще все - от чисел до стакфреймов
На C-уровне это выражено типом PyObject *
Беглый обзор “внутренностей” Python 9
Все - объект
В Python все является объектом
Ну то есть вообще все - от чисел до стакфреймов
На C-уровне это выражено типом PyObject *
Любой PyObject имеет стандартный заголовок:
#define PyObject_HEAD 
Py_ssize_t ob_refcnt; 
struct _typeobject *ob_type;
Беглый обзор “внутренностей” Python 9
Все - объект
В Python все является объектом
Ну то есть вообще все - от чисел до стакфреймов
На C-уровне это выражено типом PyObject *
Любой PyObject имеет стандартный заголовок:
#define PyObject_HEAD 
Py_ssize_t ob_refcnt; 
struct _typeobject *ob_type;
Поэтому в 64-битном Python число не может быть меньше 24
байт. Deal with it.
Беглый обзор “внутренностей” Python 9
PyObject *
#define PyObject_HEAD 
Py_ssize_t ob_refcnt; 
struct _typeobject *ob_type;
ob_refcnt - reference counter
ob_type - type object, определяющий поведение объекта и
значение полей struct’а, идущих после заголовка (например,
PyStringObject, PyIntObject)
PyObject * - указатель. Поэтому все значения в Python передаются
по ссылке. No exceptions.
Беглый обзор “внутренностей” Python 10
Ссылки
PyIntTypeObject
PyIntObject
ob_refcnt = 3
ob_type
ob_ival = 42
a b c
>>> a = b = c = 42
Все три имени ссылаются на один
объект
Этот факт можно установить при
помощи is
В общем случае == и is не
эквивалентны
Беглый обзор “внутренностей” Python 11
None
None - особый объект
Беглый обзор “внутренностей” Python 12
None
None - особый объект
Он один на каждый инстанс интерпретатора. Совсем один.
Беглый обзор “внутренностей” Python 12
None
None - особый объект
Он один на каждый инстанс интерпретатора. Совсем один.
Поэтому для него is и == всегда эквивалентны.
Беглый обзор “внутренностей” Python 12
None
None - особый объект
Он один на каждый инстанс интерпретатора. Совсем один.
Поэтому для него is и == всегда эквивалентны.
Вот так вот делать не стоит:
if x == None:
это медленно, бессмысленно и вообще плохой тон.
Беглый обзор “внутренностей” Python 12
int
int - тип “малых” целых чисел
Беглый обзор “внутренностей” Python 13
int
int - тип “малых” целых чисел
В Python целые - неизменяемый тип
Беглый обзор “внутренностей” Python 13
int
int - тип “малых” целых чисел
В Python целые - неизменяемый тип
Проверим как на них работает is:
>>> int("100") is int("100")
True
>>> int("1000") is int("1000")
False
Беглый обзор “внутренностей” Python 13
int
int - тип “малых” целых чисел
В Python целые - неизменяемый тип
Проверим как на них работает is:
>>> int("100") is int("100")
True
>>> int("1000") is int("1000")
False
Как это объяснить? Оказывается, интерпретатор “кеширует”
объекты int со значениями от -5 до 256, для других значений
создаются самостоятельные объекты.
Беглый обзор “внутренностей” Python 13
int
int - тип “малых” целых чисел
В Python целые - неизменяемый тип
Проверим как на них работает is:
>>> int("100") is int("100")
True
>>> int("1000") is int("1000")
False
Как это объяснить? Оказывается, интерпретатор “кеширует”
объекты int со значениями от -5 до 256, для других значений
создаются самостоятельные объекты.
Поэтому список intов размером до байта будет иметь overhead в 8
байт на элемент (указатель), а больших intов - до 32 байт на
элемент (указатель + объект).
Беглый обзор “внутренностей” Python 13
int
Но загадки на этом не заканчиваются:
>>> (1000 is 1000, 1000+0 is 1000+0)
(True, False)
Беглый обзор “внутренностей” Python 14
int
Но загадки на этом не заканчиваются:
>>> (1000 is 1000, 1000+0 is 1000+0)
(True, False)
Почему так - немного дальше.
Беглый обзор “внутренностей” Python 14
string
Строки, как и целые, в Python неизменяемы
Беглый обзор “внутренностей” Python 15
string
Строки, как и целые, в Python неизменяемы
Однако sharing объектов их затрагивает куда сильнее
Беглый обзор “внутренностей” Python 15
string
Строки, как и целые, в Python неизменяемы
Однако sharing объектов их затрагивает куда сильнее
Интерпретатор поддерживает dict так называемых interned
строк, для каждой из которых гарантированно существует ровно
один объект
Беглый обзор “внутренностей” Python 15
string
Строки, как и целые, в Python неизменяемы
Однако sharing объектов их затрагивает куда сильнее
Интерпретатор поддерживает dict так называемых interned
строк, для каждой из которых гарантированно существует ровно
один объект
Все идентификаторы (имена переменных, модулей, методов),
автоматически туда помещаются
Беглый обзор “внутренностей” Python 15
string
Строки, как и целые, в Python неизменяемы
Однако sharing объектов их затрагивает куда сильнее
Интерпретатор поддерживает dict так называемых interned
строк, для каждой из которых гарантированно существует ровно
один объект
Все идентификаторы (имена переменных, модулей, методов),
автоматически туда помещаются
Оператор == для interned строк выраждается в is (сравнение
указателей)
Беглый обзор “внутренностей” Python 15
string
Строки, как и целые, в Python неизменяемы
Однако sharing объектов их затрагивает куда сильнее
Интерпретатор поддерживает dict так называемых interned
строк, для каждой из которых гарантированно существует ровно
один объект
Все идентификаторы (имена переменных, модулей, методов),
автоматически туда помещаются
Оператор == для interned строк выраждается в is (сравнение
указателей)
Помимо этого, по аналогии с int со значениями [−5, 256]
разделяются объекты пустой и всех возможных однобуквенных
строк
Беглый обзор “внутренностей” Python 15
Краткий вывод
Не используйте is для чего-то кроме None
Беглый обзор “внутренностей” Python 16
Краткий вывод
Не используйте is для чего-то кроме None
Unless you know what you’re doing
Беглый обзор “внутренностей” Python 16
Байткод
Беглый обзор “внутренностей” Python 17
Виртуальная машина
“Железный” процессор не может напрямую выполнять код на C
Беглый обзор “внутренностей” Python 18
Виртуальная машина
“Железный” процессор не может напрямую выполнять код на C
Его сначала нужно “разжевать” до очень простых операций,
работающих с адресами и регистрами
Беглый обзор “внутренностей” Python 18
Виртуальная машина
“Железный” процессор не может напрямую выполнять код на C
Его сначала нужно “разжевать” до очень простых операций,
работающих с адресами и регистрами
Код на Python также не годится для непосредственного
исполнения
Беглый обзор “внутренностей” Python 18
Виртуальная машина
“Железный” процессор не может напрямую выполнять код на C
Его сначала нужно “разжевать” до очень простых операций,
работающих с адресами и регистрами
Код на Python также не годится для непосредственного
исполнения
Поэтому скрипт при загрузке транслируется в байткод
виртуальной машины
Беглый обзор “внутренностей” Python 18
Виртуальная машина
“Железный” процессор не может напрямую выполнять код на C
Его сначала нужно “разжевать” до очень простых операций,
работающих с адресами и регистрами
Код на Python также не годится для непосредственного
исполнения
Поэтому скрипт при загрузке транслируется в байткод
виртуальной машины
Виртуальная машина (VM) - это подпрограмма интерпретатора,
испоняющая байткод.
Беглый обзор “внутренностей” Python 18
Виртуальная машина
“Железный” процессор не может напрямую выполнять код на C
Его сначала нужно “разжевать” до очень простых операций,
работающих с адресами и регистрами
Код на Python также не годится для непосредственного
исполнения
Поэтому скрипт при загрузке транслируется в байткод
виртуальной машины
Виртуальная машина (VM) - это подпрограмма интерпретатора,
испоняющая байткод.
Но кроме отсутствия “железного” воплощения, концептуальных
различий с процессором нет.
Беглый обзор “внутренностей” Python 18
Байткод
Команды CPython VM кодируются одним байтом
Беглый обзор “внутренностей” Python 19
Байткод
Команды CPython VM кодируются одним байтом
Каждая из них может иметь опциональный 16-битный аргумент
Беглый обзор “внутренностей” Python 19
Байткод
Команды CPython VM кодируются одним байтом
Каждая из них может иметь опциональный 16-битный аргумент
Концептуально VM является стековой машиной (уместны
аналогии с обратной польской записью и языком Forth) -
значения кладутся на value stack (не путать с call stack), операции
их снимают с вершины и кладут результат обратно.
Беглый обзор “внутренностей” Python 19
Байткод
Команды CPython VM кодируются одним байтом
Каждая из них может иметь опциональный 16-битный аргумент
Концептуально VM является стековой машиной (уместны
аналогии с обратной польской записью и языком Forth) -
значения кладутся на value stack (не путать с call stack), операции
их снимают с вершины и кладут результат обратно.
При помощи модуля dis можно посмотреть на байткод “живых”
функций
Беглый обзор “внутренностей” Python 19
def f():
a = 1
b = 2
c = 3
return 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_MULTIPLY
28 BINARY_ADD
29 RETURN_VALUE
Беглый обзор “внутренностей” Python 20
Константы
def f(): return (1,"abc", 3.0)
Беглый обзор “внутренностей” Python 21
Константы
def f(): return (1,"abc", 3.0)
>>> dis.dis(f)
2 0 LOAD_CONST 4 ((1, ’abc’, 3.0))
3 RETURN_VALUE
Беглый обзор “внутренностей” Python 21
Константы
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
Code object
Как мы видим, байткод это не просто строка байт, так как
16-битных целых недостаточно, чтобы кодировать любые
Python-объекты
Беглый обзор “внутренностей” Python 22
Code object
Как мы видим, байткод это не просто строка байт, так как
16-битных целых недостаточно, чтобы кодировать любые
Python-объекты
Однако их достаточно, чтобы кодировать смещения. Например, в
список констант co_consts
Беглый обзор “внутренностей” Python 22
Code object
Как мы видим, байткод это не просто строка байт, так как
16-битных целых недостаточно, чтобы кодировать любые
Python-объекты
Однако их достаточно, чтобы кодировать смещения. Например, в
список констант co_consts
Наряду с другой метаинформацией (количество локальных
переменных, количество параметров, глубина стека) байткод
формирует code object
Беглый обзор “внутренностей” Python 22
Code object
Как мы видим, байткод это не просто строка байт, так как
16-битных целых недостаточно, чтобы кодировать любые
Python-объекты
Однако их достаточно, чтобы кодировать смещения. Например, в
список констант co_consts
Наряду с другой метаинформацией (количество локальных
переменных, количество параметров, глубина стека) байткод
формирует code object
Именно code object являет собой единицу существования
компилированного кода в Python
Беглый обзор “внутренностей” Python 22
Code object
Как мы видим, байткод это не просто строка байт, так как
16-битных целых недостаточно, чтобы кодировать любые
Python-объекты
Однако их достаточно, чтобы кодировать смещения. Например, в
список констант co_consts
Наряду с другой метаинформацией (количество локальных
переменных, количество параметров, глубина стека) байткод
формирует code object
Именно code object являет собой единицу существования
компилированного кода в Python
Они же сериализуются в .pyc файлы
Беглый обзор “внутренностей” Python 22
Code object
code object являются неизменяемыми
Беглый обзор “внутренностей” Python 23
Code object
code object являются неизменяемыми
В “нормальном” коде они строятся единожды - при загрузке
модуля
Беглый обзор “внутренностей” Python 23
Code object
code object являются неизменяемыми
В “нормальном” коде они строятся единожды - при загрузке
модуля
Это такой же объект как и все:
def f():
def g(): pass
return g
2 0 LOAD_CONST 1 (<code object f ...>)
3 MAKE_FUNCTION 0
6 STORE_FAST 0 (f)
3 9 LOAD_GLOBAL 0 (g)
12 RETURN_VALUE
Беглый обзор “внутренностей” Python 23
Компиляция
Процесс преобразования исходного кода модуля в набор
code object называется компиляцией
Беглый обзор “внутренностей” Python 24
Компиляция
Процесс преобразования исходного кода модуля в набор
code object называется компиляцией
Однако компилятор у Python очень рудиментарный - фактически
1-в-1 отображение конструкций в байткод
Беглый обзор “внутренностей” Python 24
Компиляция
Процесс преобразования исходного кода модуля в набор
code object называется компиляцией
Однако компилятор у Python очень рудиментарный - фактически
1-в-1 отображение конструкций в байткод
Оптимизаций уровня байткода почти нет
Беглый обзор “внутренностей” Python 24
Компиляция
Процесс преобразования исходного кода модуля в набор
code object называется компиляцией
Однако компилятор у Python очень рудиментарный - фактически
1-в-1 отображение конструкций в байткод
Оптимизаций уровня байткода почти нет
uncompyle, open source декомпилятор Python, способен
восстановить исходный код по .pyc файлу почти всегда, потеряв
при этом разве что комментарии
Беглый обзор “внутренностей” Python 24
Компиляция
Процесс преобразования исходного кода модуля в набор
code object называется компиляцией
Однако компилятор у Python очень рудиментарный - фактически
1-в-1 отображение конструкций в байткод
Оптимизаций уровня байткода почти нет
uncompyle, open source декомпилятор Python, способен
восстановить исходный код по .pyc файлу почти всегда, потеряв
при этом разве что комментарии
Так как компилятор неоптимизирующий, ему почти всегда можно
помочь (если надо)
Беглый обзор “внутренностей” Python 24
Компиляция
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
Loop hoisting
LOAD_ATTR по идее выполняется небыстро - это поиск строки с
именем метода в дикте (хеш-таблице). Строка interned, но все
равно это долго.
Беглый обзор “внутренностей” Python 26
Loop hoisting
LOAD_ATTR по идее выполняется небыстро - это поиск строки с
именем метода в дикте (хеш-таблице). Строка interned, но все
равно это долго.
Логично не выполнять эту операцию в теле цикла, а сделать ее
единожды до начала выполнения.
Беглый обзор “внутренностей” Python 26
Loop hoisting
LOAD_ATTR по идее выполняется небыстро - это поиск строки с
именем метода в дикте (хеш-таблице). Строка interned, но все
равно это долго.
Логично не выполнять эту операцию в теле цикла, а сделать ее
единожды до начала выполнения.
Эта оптимизация известна как loop hoisting, но рудиментарный
компилятор Python ее не делает.
Беглый обзор “внутренностей” Python 26
Loop hoisting
LOAD_ATTR по идее выполняется небыстро - это поиск строки с
именем метода в дикте (хеш-таблице). Строка interned, но все
равно это долго.
Логично не выполнять эту операцию в теле цикла, а сделать ее
единожды до начала выполнения.
Эта оптимизация известна как loop hoisting, но рудиментарный
компилятор Python ее не делает.
Поможем ему!
Беглый обзор “внутренностей” Python 26
Loop hoisting
def f():
l = []
la = l.append
for 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
LIST_APPEND
Добавление к списку - частая операция, и потому в CPython VM
есть особый опкод LIST_APPEND
Беглый обзор “внутренностей” Python 28
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
Неймспейсы
Беглый обзор “внутренностей” Python 29
Дикты и строки
Многие знакомые с семантикой Python люди шутят, что Гвидо ван
Россум написал dict (открытую хеш-таблицу) и string
(неизменяемые строки), после чего решил больше ничего не
писать
Беглый обзор “внутренностей” Python 30
Дикты и строки
Многие знакомые с семантикой Python люди шутят, что Гвидо ван
Россум написал dict (открытую хеш-таблицу) и string
(неизменяемые строки), после чего решил больше ничего не
писать
Действительно, объекты, модули и неймспейсы - все это обычные
дикты cо строковыми ключами
Беглый обзор “внутренностей” Python 30
Дикты и строки
Многие знакомые с семантикой Python люди шутят, что Гвидо ван
Россум написал dict (открытую хеш-таблицу) и string
(неизменяемые строки), после чего решил больше ничего не
писать
Действительно, объекты, модули и неймспейсы - все это обычные
дикты cо строковыми ключами
Глобальное пространство имен модуля, следовательно, тоже дикт,
а обращение к переменной - это lookup в дикте.
Беглый обзор “внутренностей” Python 30
Дикты и строки
Многие знакомые с семантикой Python люди шутят, что Гвидо ван
Россум написал dict (открытую хеш-таблицу) и string
(неизменяемые строки), после чего решил больше ничего не
писать
Действительно, объекты, модули и неймспейсы - все это обычные
дикты cо строковыми ключами
Глобальное пространство имен модуля, следовательно, тоже дикт,
а обращение к переменной - это lookup в дикте.
Всегда ли это так?
Беглый обзор “внутренностей” Python 30
Дикты и строки
def f():
a = 3
return 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_ADD
13 RETURN_VALUE
Беглый обзор “внутренностей” Python 31
LOAD_FAST и LOAD_GLOBAL
3 6 LOAD_FAST 0 (a)
9 LOAD_GLOBAL 0 (b)
Для имен a и b компилятор использовал разные опкоды. Почему?
Беглый обзор “внутренностей” Python 32
LOAD_FAST и LOAD_GLOBAL
3 6 LOAD_FAST 0 (a)
9 LOAD_GLOBAL 0 (b)
Для имен a и b компилятор использовал разные опкоды. Почему?
Оказывается, на этапе компиляции в code object собираются все
имена локальных переменных (то есть присваиваемые в этом
блоке кода и не помеченные явно при помощи global), и
заносятся в список co_locals.
Беглый обзор “внутренностей” Python 32
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
LOAD_FAST и LOAD_GLOBAL
LOAD_FAST, как нетрудно догадаться, просто берет значение по
индексу из массива
Беглый обзор “внутренностей” Python 33
LOAD_FAST и LOAD_GLOBAL
LOAD_FAST, как нетрудно догадаться, просто берет значение по
индексу из массива
LOAD_GLOBAL же вынужден брать строку с именем из co_consts,
после чего искать по этому ключу в дикте неймспейса
Беглый обзор “внутренностей” Python 33
LOAD_FAST и LOAD_GLOBAL
LOAD_FAST, как нетрудно догадаться, просто берет значение по
индексу из массива
LOAD_GLOBAL же вынужден брать строку с именем из co_consts,
после чего искать по этому ключу в дикте неймспейса
Обе операции выполняются с ожидаемой стоимостью O(1), но у
массива константа явно лучше
Беглый обзор “внутренностей” Python 33
LOAD_FAST и LOAD_GLOBAL
LOAD_FAST, как нетрудно догадаться, просто берет значение по
индексу из массива
LOAD_GLOBAL же вынужден брать строку с именем из co_consts,
после чего искать по этому ключу в дикте неймспейса
Обе операции выполняются с ожидаемой стоимостью O(1), но у
массива константа явно лучше
Поэтому закешировать что-то в локальную переменную не самая
плохая идея в плане производительности
Беглый обзор “внутренностей” Python 33
Lexical scoping
Глобальный и локальный неймспейсы достаточно очевидны сами
по себе
Беглый обзор “внутренностей” Python 34
Lexical scoping
Глобальный и локальный неймспейсы достаточно очевидны сами
по себе
Однако Python позволяет делать вот так:
def f():
a = 1
def g(): return a
return g
>>> t = f()
>>> t()
1
Беглый обзор “внутренностей” Python 34
Lexical scoping
Глобальный и локальный неймспейсы достаточно очевидны сами
по себе
Однако Python позволяет делать вот так:
def f():
a = 1
def g(): return a
return g
>>> t = f()
>>> t()
1
Как возвращенной функции удается вернуть значение из
разрушенного фрейма?
Беглый обзор “внутренностей” Python 34
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 0
18 STORE_FAST 0 (g)
4 21 LOAD_FAST 0 (g)
24 RETURN_VALUE
Беглый обзор “внутренностей” Python 35
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 0
18 STORE_FAST 0 (g)
4 21 LOAD_FAST 0 (g)
24 RETURN_VALUE
cell object - это код функции вместе со значениями “внешних”
(свободных, free) переменных
Беглый обзор “внутренностей” Python 35
Lexical scoping
cell object по времени жизни не привязан к фрейму, в котором
он создан, и собирается сборщиком мусора только тогда, когда
станет недостижим.
Беглый обзор “внутренностей” Python 36
Lexical scoping
cell object по времени жизни не привязан к фрейму, в котором
он создан, и собирается сборщиком мусора только тогда, когда
станет недостижим.
Это “взрослая” реализация лексической области видимости
Беглый обзор “внутренностей” Python 36
Lexical scoping
cell object по времени жизни не привязан к фрейму, в котором
он создан, и собирается сборщиком мусора только тогда, когда
станет недостижим.
Это “взрослая” реализация лексической области видимости
Однако, к сожалению, она неполна:
def f():
a = 1
if True: a = 2; print a
print a
этот код выведет 2 2. Аналогичный код на C++, или, скажем,
Lua, выдаст 2 1
Беглый обзор “внутренностей” Python 36
Lexical scoping
cell object по времени жизни не привязан к фрейму, в котором
он создан, и собирается сборщиком мусора только тогда, когда
станет недостижим.
Это “взрослая” реализация лексической области видимости
Однако, к сожалению, она неполна:
def f():
a = 1
if True: a = 2; print a
print a
этот код выведет 2 2. Аналогичный код на C++, или, скажем,
Lua, выдаст 2 1
Это источник трудноуловимых багов
Беглый обзор “внутренностей” Python 36
Выстрелить в ногу!
Что выведет это код?
l = [lambda: x for x in "abcdefg"]
for r in l: print r(),
Беглый обзор “внутренностей” Python 37
Выстрелить в ногу!
Что выведет это код?
l = [lambda: x for x in "abcdefg"]
for r in l: print r(),
Наверное a b c d e f g?
Беглый обзор “внутренностей” Python 37
Выстрелить в ногу!
Что выведет это код?
l = [lambda: x for x in "abcdefg"]
for r in l: print r(),
Наверное a b c d e f g?
Реальность жестока.
Беглый обзор “внутренностей” Python 37
Выстрелить в ногу!
Что выведет это код?
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
Lexical scoping
К сожалению, различие поведения областей видимости на макро-
и микроуровнях настолько глубоко зашито в архитектуре языка,
что поправить его практически нереально
Беглый обзор “внутренностей” Python 38
Lexical scoping
К сожалению, различие поведения областей видимости на макро-
и микроуровнях настолько глубоко зашито в архитектуре языка,
что поправить его практически нереально
Даже если это сделать - это с большой вероятностью приведет к
“ломанию” имеющегося кода
Беглый обзор “внутренностей” Python 38
Lexical scoping
К сожалению, различие поведения областей видимости на макро-
и микроуровнях настолько глубоко зашито в архитектуре языка,
что поправить его практически нереально
Даже если это сделать - это с большой вероятностью приведет к
“ломанию” имеющегося кода
Поэтому про данную особенность надо просто помнить, и не
сильно увлекаться функциональным программированием на
Python ;)
Беглый обзор “внутренностей” Python 38
Заключение
Беглый обзор “внутренностей” Python 39
Заключение
К сожалению, регламент данного доклада не дает слишком
разогнаться. За бортом остаются многие интересные темы:
Беглый обзор “внутренностей” Python 40
Заключение
К сожалению, регламент данного доклада не дает слишком
разогнаться. За бортом остаются многие интересные темы:
Global Interpreter Lock (GIL), или почему программы на Python на
нескольких ядрах работают медленнее, чем на одном
Беглый обзор “внутренностей” Python 40
Заключение
К сожалению, регламент данного доклада не дает слишком
разогнаться. За бортом остаются многие интересные темы:
Global Interpreter Lock (GIL), или почему программы на Python на
нескольких ядрах работают медленнее, чем на одном
frame object и их список, или как greenlet умудряется
эмулировать кооперативную многозадачность “срезанием” стека
Беглый обзор “внутренностей” Python 40
Заключение
К сожалению, регламент данного доклада не дает слишком
разогнаться. За бортом остаются многие интересные темы:
Global Interpreter Lock (GIL), или почему программы на Python на
нескольких ядрах работают медленнее, чем на одном
frame object и их список, или как greenlet умудряется
эмулировать кооперативную многозадачность “срезанием” стека
ООП в Python, или почему у object нельзя выставить атрибут, а
у унаследованного от него пустого класса - можно
Беглый обзор “внутренностей” Python 40
Заключение
К сожалению, регламент данного доклада не дает слишком
разогнаться. За бортом остаются многие интересные темы:
Global Interpreter Lock (GIL), или почему программы на Python на
нескольких ядрах работают медленнее, чем на одном
frame object и их список, или как greenlet умудряется
эмулировать кооперативную многозадачность “срезанием” стека
ООП в Python, или почему у object нельзя выставить атрибут, а
у унаследованного от него пустого класса - можно
Генераторы, или как “шаманство” с фреймами позволяет
создавать видимость их (генераторов) наличия, но с серьезными
ограничениями
Беглый обзор “внутренностей” Python 40
Заключение
Однако большой проблемы нет - это не сакральное знание
Беглый обзор “внутренностей” Python 41
Заключение
Однако большой проблемы нет - это не сакральное знание
Все, что я вам сегодня рассказал, я не прочитал в интернете и на
StackOverflow - я прочитал это в исходных кодах интерпретатора
Беглый обзор “внутренностей” Python 41
Заключение
Однако большой проблемы нет - это не сакральное знание
Все, что я вам сегодня рассказал, я не прочитал в интернете и на
StackOverflow - я прочитал это в исходных кодах интерпретатора
Они действительно неплохо структурированы и их довольно
просто читать, даже людям без соответствующего бэкграунда
Беглый обзор “внутренностей” Python 41
Заключение
Однако большой проблемы нет - это не сакральное знание
Все, что я вам сегодня рассказал, я не прочитал в интернете и на
StackOverflow - я прочитал это в исходных кодах интерпретатора
Они действительно неплохо структурированы и их довольно
просто читать, даже людям без соответствующего бэкграунда
Мне это помогло глубже понять как работает тот код, который я
пишу, что порой оказывалось очень полезным при профайлинге
критичных мест
Беглый обзор “внутренностей” Python 41
Заключение
Однако большой проблемы нет - это не сакральное знание
Все, что я вам сегодня рассказал, я не прочитал в интернете и на
StackOverflow - я прочитал это в исходных кодах интерпретатора
Они действительно неплохо структурированы и их довольно
просто читать, даже людям без соответствующего бэкграунда
Мне это помогло глубже понять как работает тот код, который я
пишу, что порой оказывалось очень полезным при профайлинге
критичных мест
Это как раз тот случай, когда вместо того, чтобы лезть на
StackOverflow, полезнее и интереснее разобраться самому. Так
что дерзайте!
Беглый обзор “внутренностей” Python 41
Благодарю за внимание!
Вопросы?

Más contenido relacionado

La actualidad más candente

Введение в потоки питона
Введение в потоки питонаВведение в потоки питона
Введение в потоки питонаAndrey Niahajchyk
 
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотекSWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотекPython Meetup
 
"Модифицируй это!" или "Больше магии Python с помощью изменения AST"
"Модифицируй это!" или "Больше магии Python с помощью изменения AST""Модифицируй это!" или "Больше магии Python с помощью изменения AST"
"Модифицируй это!" или "Больше магии Python с помощью изменения AST"PyNSK
 
Беглый обзор "внутренностей" Python
Беглый обзор "внутренностей" PythonБеглый обзор "внутренностей" Python
Беглый обзор "внутренностей" PythonMaxim Kulsha
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Yandex
 
Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...
Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...
Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...Stas Vyschepan
 
Мой Python всегда со мной!
Мой Python всегда со мной!Мой Python всегда со мной!
Мой Python всегда со мной!PyNSK
 
Internationalization and localization of the python applications with gettext...
Internationalization and localization of the python applications with gettext...Internationalization and localization of the python applications with gettext...
Internationalization and localization of the python applications with gettext...Volodymyr Hotsyk
 
Go для python-программистов
Go для python-программистовGo для python-программистов
Go для python-программистовKonstantin Cherkasov
 
poudriere или как я перестал волноваться и полюбил pkg
poudriere или как я перестал волноваться и полюбил pkgpoudriere или как я перестал волноваться и полюбил pkg
poudriere или как я перестал волноваться и полюбил pkgAndrey Fesenko
 
Aviasales: миграция поискового движка в docker / Дмитрий Кузьменков (Aviasales)
Aviasales: миграция поискового движка в docker / Дмитрий Кузьменков (Aviasales)Aviasales: миграция поискового движка в docker / Дмитрий Кузьменков (Aviasales)
Aviasales: миграция поискового движка в docker / Дмитрий Кузьменков (Aviasales)Ontico
 
14 HappyDev-lite-2015 autumn. Дмитрий Вахрушев. Зачем вам изучать Python?
14 HappyDev-lite-2015 autumn. Дмитрий Вахрушев. Зачем вам изучать Python?14 HappyDev-lite-2015 autumn. Дмитрий Вахрушев. Зачем вам изучать Python?
14 HappyDev-lite-2015 autumn. Дмитрий Вахрушев. Зачем вам изучать Python?HappyDev-lite
 
[Defcon Russia #29] Михаил Клементьев - Обнаружение руткитов в GNU/Linux
[Defcon Russia #29] Михаил Клементьев - Обнаружение руткитов в GNU/Linux[Defcon Russia #29] Михаил Клементьев - Обнаружение руткитов в GNU/Linux
[Defcon Russia #29] Михаил Клементьев - Обнаружение руткитов в GNU/LinuxDefconRussia
 
Илья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The Grinder
Илья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The GrinderИлья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The Grinder
Илья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The GrinderSQALab
 
Ubuntu+python+selenium=легкий старт
Ubuntu+python+selenium=легкий стартUbuntu+python+selenium=легкий старт
Ubuntu+python+selenium=легкий стартAndrey Matukhno
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаSergey Platonov
 
Введение в динамический анализ приложений на примере Intel Pin
Введение в динамический анализ приложений на примере Intel PinВведение в динамический анализ приложений на примере Intel Pin
Введение в динамический анализ приложений на примере Intel PinSemen Martynov
 
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)Ontico
 

La actualidad más candente (20)

Введение в потоки питона
Введение в потоки питонаВведение в потоки питона
Введение в потоки питона
 
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотекSWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
SWIG — cоздание мультиязыковых интерфейсов для C/C++ библиотек
 
"Модифицируй это!" или "Больше магии Python с помощью изменения AST"
"Модифицируй это!" или "Больше магии Python с помощью изменения AST""Модифицируй это!" или "Больше магии Python с помощью изменения AST"
"Модифицируй это!" или "Больше магии Python с помощью изменения AST"
 
Беглый обзор "внутренностей" Python
Беглый обзор "внутренностей" PythonБеглый обзор "внутренностей" Python
Беглый обзор "внутренностей" Python
 
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
Руслан Гроховецкий "Как Python стал делать погоду в Яндексе"
 
Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...
Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...
Оптимизация высоконагруженных ASP.NET приложений, работающих с MS SQL Server ...
 
Мой Python всегда со мной!
Мой Python всегда со мной!Мой Python всегда со мной!
Мой Python всегда со мной!
 
Internationalization and localization of the python applications with gettext...
Internationalization and localization of the python applications with gettext...Internationalization and localization of the python applications with gettext...
Internationalization and localization of the python applications with gettext...
 
Kotlin with API tests
Kotlin with API testsKotlin with API tests
Kotlin with API tests
 
Go для python-программистов
Go для python-программистовGo для python-программистов
Go для python-программистов
 
poudriere или как я перестал волноваться и полюбил pkg
poudriere или как я перестал волноваться и полюбил pkgpoudriere или как я перестал волноваться и полюбил pkg
poudriere или как я перестал волноваться и полюбил pkg
 
Aviasales: миграция поискового движка в docker / Дмитрий Кузьменков (Aviasales)
Aviasales: миграция поискового движка в docker / Дмитрий Кузьменков (Aviasales)Aviasales: миграция поискового движка в docker / Дмитрий Кузьменков (Aviasales)
Aviasales: миграция поискового движка в docker / Дмитрий Кузьменков (Aviasales)
 
14 HappyDev-lite-2015 autumn. Дмитрий Вахрушев. Зачем вам изучать Python?
14 HappyDev-lite-2015 autumn. Дмитрий Вахрушев. Зачем вам изучать Python?14 HappyDev-lite-2015 autumn. Дмитрий Вахрушев. Зачем вам изучать Python?
14 HappyDev-lite-2015 autumn. Дмитрий Вахрушев. Зачем вам изучать Python?
 
[Defcon Russia #29] Михаил Клементьев - Обнаружение руткитов в GNU/Linux
[Defcon Russia #29] Михаил Клементьев - Обнаружение руткитов в GNU/Linux[Defcon Russia #29] Михаил Клементьев - Обнаружение руткитов в GNU/Linux
[Defcon Russia #29] Михаил Клементьев - Обнаружение руткитов в GNU/Linux
 
Илья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The Grinder
Илья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The GrinderИлья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The Grinder
Илья Евлампиев - Нагрузочное тестирование веб-приложений с помощью The Grinder
 
Ubuntu+python+selenium=легкий старт
Ubuntu+python+selenium=легкий стартUbuntu+python+selenium=легкий старт
Ubuntu+python+selenium=легкий старт
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
Отладка в Python: 2016 edition
Отладка в Python: 2016 editionОтладка в Python: 2016 edition
Отладка в Python: 2016 edition
 
Введение в динамический анализ приложений на примере Intel Pin
Введение в динамический анализ приложений на примере Intel PinВведение в динамический анализ приложений на примере Intel Pin
Введение в динамический анализ приложений на примере Intel Pin
 
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
Сравнение форматов и библиотек сериализации / Антон Рыжов (Qrator Labs)
 

Destacado

Вячеслав Бирюков - Linux инструменты системного администратора
Вячеслав Бирюков - Linux инструменты системного администратора Вячеслав Бирюков - Linux инструменты системного администратора
Вячеслав Бирюков - Linux инструменты системного администратора Yandex
 
Введение в Python и Django
Введение в Python и DjangoВведение в Python и Django
Введение в Python и DjangoTaras Lyapun
 
Введение в язык программирования Питон (Python)
Введение в язык программирования Питон (Python)Введение в язык программирования Питон (Python)
Введение в язык программирования Питон (Python)Александр Дьяконов
 
Лекция 2. Всё, что вы хотели знать о функциях в Python.
Лекция 2. Всё, что вы хотели знать о функциях в Python.Лекция 2. Всё, что вы хотели знать о функциях в Python.
Лекция 2. Всё, что вы хотели знать о функциях в Python.Roman Brovko
 
Intro to Linux Shell Scripting
Intro to Linux Shell ScriptingIntro to Linux Shell Scripting
Intro to Linux Shell Scriptingvceder
 
2015 Upload Campaigns Calendar - SlideShare
2015 Upload Campaigns Calendar - SlideShare2015 Upload Campaigns Calendar - SlideShare
2015 Upload Campaigns Calendar - SlideShareSlideShare
 
What to Upload to SlideShare
What to Upload to SlideShareWhat to Upload to SlideShare
What to Upload to SlideShareSlideShare
 
Getting Started With SlideShare
Getting Started With SlideShareGetting Started With SlideShare
Getting Started With SlideShareSlideShare
 

Destacado (9)

Вячеслав Бирюков - Linux инструменты системного администратора
Вячеслав Бирюков - Linux инструменты системного администратора Вячеслав Бирюков - Linux инструменты системного администратора
Вячеслав Бирюков - Linux инструменты системного администратора
 
Введение в Python и Django
Введение в Python и DjangoВведение в Python и Django
Введение в Python и Django
 
Введение в язык программирования Питон (Python)
Введение в язык программирования Питон (Python)Введение в язык программирования Питон (Python)
Введение в язык программирования Питон (Python)
 
Лекция 2. Всё, что вы хотели знать о функциях в Python.
Лекция 2. Всё, что вы хотели знать о функциях в Python.Лекция 2. Всё, что вы хотели знать о функциях в Python.
Лекция 2. Всё, что вы хотели знать о функциях в Python.
 
Shell scripting
Shell scriptingShell scripting
Shell scripting
 
Intro to Linux Shell Scripting
Intro to Linux Shell ScriptingIntro to Linux Shell Scripting
Intro to Linux Shell Scripting
 
2015 Upload Campaigns Calendar - SlideShare
2015 Upload Campaigns Calendar - SlideShare2015 Upload Campaigns Calendar - SlideShare
2015 Upload Campaigns Calendar - SlideShare
 
What to Upload to SlideShare
What to Upload to SlideShareWhat to Upload to SlideShare
What to Upload to SlideShare
 
Getting Started With SlideShare
Getting Started With SlideShareGetting Started With SlideShare
Getting Started With SlideShare
 

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

Python и высокая нагрузка
Python и высокая нагрузкаPython и высокая нагрузка
Python и высокая нагрузкаAlexander Shigin
 
409bb948 9463-4d6b-b885-63955ea67f1e-210512195958
409bb948 9463-4d6b-b885-63955ea67f1e-210512195958409bb948 9463-4d6b-b885-63955ea67f1e-210512195958
409bb948 9463-4d6b-b885-63955ea67f1e-210512195958vavaxd
 
Python-технология которую легко продавать!
Python-технология которую легко продавать!Python-технология которую легко продавать!
Python-технология которую легко продавать!Aleksey Nakorenko
 
Natural Language Processing (NLP) with .NET for #dotnetby meetup-29
Natural Language Processing (NLP) with .NET for #dotnetby meetup-29Natural Language Processing (NLP) with .NET for #dotnetby meetup-29
Natural Language Processing (NLP) with .NET for #dotnetby meetup-29Sergey Tihon
 
Easy selenium test automation on python
Easy selenium test automation on pythonEasy selenium test automation on python
Easy selenium test automation on pythonMykhailo Poliarush
 
ekbpy'2012 - Марк Коренберг - Системное программирование на Питоне
ekbpy'2012 - Марк Коренберг - Системное программирование на Питонеekbpy'2012 - Марк Коренберг - Системное программирование на Питоне
ekbpy'2012 - Марк Коренберг - Системное программирование на Питонеit-people
 
Чем Python плох для стартапа?
Чем Python плох для стартапа?Чем Python плох для стартапа?
Чем Python плох для стартапа?PyNSK
 
Django. Web project full circle
Django. Web project full circleDjango. Web project full circle
Django. Web project full circlewebriders
 
Py con 2010_django_project_dev_full_circle
Py con 2010_django_project_dev_full_circlePy con 2010_django_project_dev_full_circle
Py con 2010_django_project_dev_full_circleRostislav Bryzgunov
 
Django. Web project full circle
Django. Web project full circleDjango. Web project full circle
Django. Web project full circleOlexiy Strashko
 
Что отличает джуниора от сениора или как питонисту не иметь проблем с поиском...
Что отличает джуниора от сениора или как питонисту не иметь проблем с поиском...Что отличает джуниора от сениора или как питонисту не иметь проблем с поиском...
Что отличает джуниора от сениора или как питонисту не иметь проблем с поиском...Mail.ru Group
 
Функциональный .NET
Функциональный .NETФункциональный .NET
Функциональный .NETRoman Nevolin
 
Путь дата аналитика
Путь дата аналитикаПуть дата аналитика
Путь дата аналитикаAUTODOC
 
Макс Волошин: Php + shell = ♥
Макс Волошин: Php + shell = ♥Макс Волошин: Php + shell = ♥
Макс Волошин: Php + shell = ♥Oleg Poludnenko
 
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...Anthony Marchenko
 
Поговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложенийПоговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложенийAndrey Akinshin
 

Similar a Беглый обзор "внутренностей" Python (20)

Python и высокая нагрузка
Python и высокая нагрузкаPython и высокая нагрузка
Python и высокая нагрузка
 
409bb948 9463-4d6b-b885-63955ea67f1e-210512195958
409bb948 9463-4d6b-b885-63955ea67f1e-210512195958409bb948 9463-4d6b-b885-63955ea67f1e-210512195958
409bb948 9463-4d6b-b885-63955ea67f1e-210512195958
 
Python-технология которую легко продавать!
Python-технология которую легко продавать!Python-технология которую легко продавать!
Python-технология которую легко продавать!
 
Python и Cython
Python и CythonPython и Cython
Python и Cython
 
Natural Language Processing (NLP) with .NET for #dotnetby meetup-29
Natural Language Processing (NLP) with .NET for #dotnetby meetup-29Natural Language Processing (NLP) with .NET for #dotnetby meetup-29
Natural Language Processing (NLP) with .NET for #dotnetby meetup-29
 
Easy selenium test automation on python
Easy selenium test automation on pythonEasy selenium test automation on python
Easy selenium test automation on python
 
ekbpy'2012 - Марк Коренберг - Системное программирование на Питоне
ekbpy'2012 - Марк Коренберг - Системное программирование на Питонеekbpy'2012 - Марк Коренберг - Системное программирование на Питоне
ekbpy'2012 - Марк Коренберг - Системное программирование на Питоне
 
Чем Python плох для стартапа?
Чем Python плох для стартапа?Чем Python плох для стартапа?
Чем Python плох для стартапа?
 
Django. Web project full circle
Django. Web project full circleDjango. Web project full circle
Django. Web project full circle
 
Py con 2010_django_project_dev_full_circle
Py con 2010_django_project_dev_full_circlePy con 2010_django_project_dev_full_circle
Py con 2010_django_project_dev_full_circle
 
Django. Web project full circle
Django. Web project full circleDjango. Web project full circle
Django. Web project full circle
 
Что отличает джуниора от сениора или как питонисту не иметь проблем с поиском...
Что отличает джуниора от сениора или как питонисту не иметь проблем с поиском...Что отличает джуниора от сениора или как питонисту не иметь проблем с поиском...
Что отличает джуниора от сениора или как питонисту не иметь проблем с поиском...
 
Функциональный .NET
Функциональный .NETФункциональный .NET
Функциональный .NET
 
Путь дата аналитика
Путь дата аналитикаПуть дата аналитика
Путь дата аналитика
 
6
66
6
 
Макс Волошин: Php + shell = ♥
Макс Волошин: Php + shell = ♥Макс Волошин: Php + shell = ♥
Макс Волошин: Php + shell = ♥
 
idioms C++
idioms C++idioms C++
idioms C++
 
C++ idioms
C++ idiomsC++ idioms
C++ idioms
 
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
Встраивание Python в мобильные приложения – нюансы interoperation, новые подх...
 
Поговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложенийПоговорим о микрооптимизациях .NET-приложений
Поговорим о микрооптимизациях .NET-приложений
 

Más de Python Meetup

Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15] Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15] Python Meetup
 
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...Python Meetup
 
Python&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython Meetup
 
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...Python Meetup
 
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...Python Meetup
 
Про асинхронность / Максим Щепелин / Web Developer Wargaming
Про асинхронность / Максим Щепелин / Web Developer WargamingПро асинхронность / Максим Щепелин / Web Developer Wargaming
Про асинхронность / Максим Щепелин / Web Developer WargamingPython Meetup
 
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014Python Meetup
 
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014Python Meetup
 
Wargaming: тыл - фронту!
Wargaming: тыл - фронту!Wargaming: тыл - фронту!
Wargaming: тыл - фронту!Python Meetup
 
Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Python Meetup
 
Redis. Как мы боролись со сложностью
Redis. Как мы боролись со сложностьюRedis. Как мы боролись со сложностью
Redis. Как мы боролись со сложностьюPython Meetup
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка TwistedPython Meetup
 
Обзор способов написания конкурентных программ в питоне
Обзор способов написания конкурентных программ в питоне Обзор способов написания конкурентных программ в питоне
Обзор способов написания конкурентных программ в питоне Python Meetup
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеPython Meetup
 
Python для анализа данных
Python для анализа данныхPython для анализа данных
Python для анализа данныхPython Meetup
 
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...Python Meetup
 
Использование gevent для эмуляции высокой нагрузки
Использование gevent для эмуляции высокой нагрузкиИспользование gevent для эмуляции высокой нагрузки
Использование gevent для эмуляции высокой нагрузкиPython Meetup
 
Введение в GIL и новый GIL
Введение в GIL и новый GILВведение в GIL и новый GIL
Введение в GIL и новый GILPython Meetup
 
Недостатки Python
Недостатки PythonНедостатки Python
Недостатки PythonPython Meetup
 

Más de Python Meetup (20)

Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15] Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
Machine learning with Python / Олег Шидловский / Doist [Python Meetup 27.03.15]
 
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
Как скачать статистику игроков World of Tanks / Павел Пересторонин [Python Me...
 
Python&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.byPython&Printer / Андрей Пучко / penta.by
Python&Printer / Андрей Пучко / penta.by
 
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
Почему я пишу хороший код, но его никто не ценит, кроме моей мамы / Павел Меш...
 
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
OpenSource CMS и ERP система в одном флаконе / Олег Курьян / технический дире...
 
Про асинхронность / Максим Щепелин / Web Developer Wargaming
Про асинхронность / Максим Щепелин / Web Developer WargamingПро асинхронность / Максим Щепелин / Web Developer Wargaming
Про асинхронность / Максим Щепелин / Web Developer Wargaming
 
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
S.O.L.I.D. - Павел Кохан, Python Meetup 26.09.2014
 
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
Быстрые конструкции в Python - Олег Шидловский, Python Meetup 26.09.2014
 
Wargaming: тыл - фронту!
Wargaming: тыл - фронту!Wargaming: тыл - фронту!
Wargaming: тыл - фронту!
 
Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"Максим Щепелин. "Unittesting. Как?"
Максим Щепелин. "Unittesting. Как?"
 
Redis. Как мы боролись со сложностью
Redis. Как мы боролись со сложностьюRedis. Как мы боролись со сложностью
Redis. Как мы боролись со сложностью
 
Обзор фреймворка Twisted
Обзор фреймворка TwistedОбзор фреймворка Twisted
Обзор фреймворка Twisted
 
Обзор способов написания конкурентных программ в питоне
Обзор способов написания конкурентных программ в питоне Обзор способов написания конкурентных программ в питоне
Обзор способов написания конкурентных программ в питоне
 
Pebble
PebblePebble
Pebble
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгирование
 
Python для анализа данных
Python для анализа данныхPython для анализа данных
Python для анализа данных
 
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
Асинхронное распределенное выполнение задач. Stdlib, Celery, RQ и собственные...
 
Использование gevent для эмуляции высокой нагрузки
Использование gevent для эмуляции высокой нагрузкиИспользование gevent для эмуляции высокой нагрузки
Использование gevent для эмуляции высокой нагрузки
 
Введение в GIL и новый GIL
Введение в GIL и новый GILВведение в GIL и новый GIL
Введение в GIL и новый GIL
 
Недостатки Python
Недостатки PythonНедостатки Python
Недостатки Python
 

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

  • 1. Беглый обзор “внутренностей” Python Никита Лесников
  • 2. Почему это может быть полезно? Часто у программиста, использующего в работе Python, возникает один из следующих вопросов: какой из двух способов решения проблемы потребляет меньше памяти? Беглый обзор “внутренностей” Python 2
  • 3. Почему это может быть полезно? Часто у программиста, использующего в работе Python, возникает один из следующих вопросов: какой из двух способов решения проблемы потребляет меньше памяти? какой из двух способов работает быстрее? Беглый обзор “внутренностей” Python 2
  • 4. Почему это может быть полезно? Часто у программиста, использующего в работе Python, возникает один из следующих вопросов: какой из двух способов решения проблемы потребляет меньше памяти? какой из двух способов работает быстрее? как поведет себя определенная конструкция при изменении runtime среды? Беглый обзор “внутренностей” Python 2
  • 5. Почему это может быть полезно? Решаются они обычно одним из следующих способов: можно спросить у коллег Беглый обзор “внутренностей” Python 3
  • 6. Почему это может быть полезно? Решаются они обычно одним из следующих способов: можно спросить у коллег можно найти ответ на StackOverflow Беглый обзор “внутренностей” Python 3
  • 7. Почему это может быть полезно? Решаются они обычно одним из следующих способов: можно спросить у коллег можно найти ответ на StackOverflow можно замерить самому Беглый обзор “внутренностей” Python 3
  • 8. Почему это может быть полезно? Однако понимание того, как работает интерпретатор на самых нижних уровнях, позволяет обрести интуитивное понимание нюансов работы многих конструкций языка. Беглый обзор “внутренностей” Python 4
  • 9. Почему это может быть полезно? Однако понимание того, как работает интерпретатор на самых нижних уровнях, позволяет обрести интуитивное понимание нюансов работы многих конструкций языка. Кроме того, в случае с Python абсолютное большинство программистов обладает достаточной квалификацией, чтобы без посредников найти ответ на свой вопрос в исходниках интерпретатора. Беглый обзор “внутренностей” Python 4
  • 10. Почему это может быть полезно? Знакомство с “внутренностями” полезно также потому, что Python является open source проектом - кто знает, быть может именно вы решите одну из наболевших проблем? ;) Беглый обзор “внутренностей” Python 5
  • 11. Почему это может быть полезно? Знакомство с “внутренностями” полезно также потому, что Python является open source проектом - кто знает, быть может именно вы решите одну из наболевших проблем? ;) Кратким изучением наиболее характерных особенностей интерпретатора мы сейчас и займемся. Беглый обзор “внутренностей” Python 5
  • 12. CPython Основная реализация Python на сегодняшний день Беглый обзор “внутренностей” Python 6
  • 13. CPython Основная реализация Python на сегодняшний день Написана на C (не С++), кроссплатформенна и довольно легко переносима на отличные от официально поддерживаемых платформы Беглый обзор “внутренностей” Python 6
  • 14. CPython Основная реализация Python на сегодняшний день Написана на C (не С++), кроссплатформенна и довольно легко переносима на отличные от официально поддерживаемых платформы Код простой и понятный Беглый обзор “внутренностей” Python 6
  • 15. CPython Основная реализация Python на сегодняшний день Написана на C (не С++), кроссплатформенна и довольно легко переносима на отличные от официально поддерживаемых платформы Код простой и понятный Нет, серьезно, простой и понятный, даже для людей, не интересующихся разработкой языков программирования ;) Беглый обзор “внутренностей” Python 6
  • 16. CPython Есть еще PyPy, IronPython, Jython, Boo (хотя это не совсем Python) Беглый обзор “внутренностей” Python 7
  • 17. CPython Есть еще PyPy, IronPython, Jython, Boo (хотя это не совсем Python) Они по своему интересны, но с CPython “внутри” у них мало общего Беглый обзор “внутренностей” Python 7
  • 18. CPython Есть еще PyPy, IronPython, Jython, Boo (хотя это не совсем Python) Они по своему интересны, но с CPython “внутри” у них мало общего Поэтому хотя они и могут быть очень полезны на практике, рассматривать их мы не будем Беглый обзор “внутренностей” Python 7
  • 19. Все - объект. Беглый обзор “внутренностей” Python 8
  • 20. Все - объект В Python все является объектом Беглый обзор “внутренностей” Python 9
  • 21. Все - объект В Python все является объектом Ну то есть вообще все - от чисел до стакфреймов Беглый обзор “внутренностей” Python 9
  • 22. Все - объект В Python все является объектом Ну то есть вообще все - от чисел до стакфреймов На C-уровне это выражено типом PyObject * Беглый обзор “внутренностей” Python 9
  • 23. Все - объект В Python все является объектом Ну то есть вообще все - от чисел до стакфреймов На C-уровне это выражено типом PyObject * Любой PyObject имеет стандартный заголовок: #define PyObject_HEAD Py_ssize_t ob_refcnt; struct _typeobject *ob_type; Беглый обзор “внутренностей” Python 9
  • 24. Все - объект В Python все является объектом Ну то есть вообще все - от чисел до стакфреймов На C-уровне это выражено типом PyObject * Любой PyObject имеет стандартный заголовок: #define PyObject_HEAD Py_ssize_t ob_refcnt; struct _typeobject *ob_type; Поэтому в 64-битном Python число не может быть меньше 24 байт. Deal with it. Беглый обзор “внутренностей” Python 9
  • 25. PyObject * #define PyObject_HEAD Py_ssize_t ob_refcnt; struct _typeobject *ob_type; ob_refcnt - reference counter ob_type - type object, определяющий поведение объекта и значение полей struct’а, идущих после заголовка (например, PyStringObject, PyIntObject) PyObject * - указатель. Поэтому все значения в Python передаются по ссылке. No exceptions. Беглый обзор “внутренностей” Python 10
  • 26. Ссылки PyIntTypeObject PyIntObject ob_refcnt = 3 ob_type ob_ival = 42 a b c >>> a = b = c = 42 Все три имени ссылаются на один объект Этот факт можно установить при помощи is В общем случае == и is не эквивалентны Беглый обзор “внутренностей” Python 11
  • 27. None None - особый объект Беглый обзор “внутренностей” Python 12
  • 28. None None - особый объект Он один на каждый инстанс интерпретатора. Совсем один. Беглый обзор “внутренностей” Python 12
  • 29. None None - особый объект Он один на каждый инстанс интерпретатора. Совсем один. Поэтому для него is и == всегда эквивалентны. Беглый обзор “внутренностей” Python 12
  • 30. None None - особый объект Он один на каждый инстанс интерпретатора. Совсем один. Поэтому для него is и == всегда эквивалентны. Вот так вот делать не стоит: if x == None: это медленно, бессмысленно и вообще плохой тон. Беглый обзор “внутренностей” Python 12
  • 31. int int - тип “малых” целых чисел Беглый обзор “внутренностей” Python 13
  • 32. int int - тип “малых” целых чисел В Python целые - неизменяемый тип Беглый обзор “внутренностей” Python 13
  • 33. int int - тип “малых” целых чисел В Python целые - неизменяемый тип Проверим как на них работает is: >>> int("100") is int("100") True >>> int("1000") is int("1000") False Беглый обзор “внутренностей” Python 13
  • 34. int int - тип “малых” целых чисел В Python целые - неизменяемый тип Проверим как на них работает is: >>> int("100") is int("100") True >>> int("1000") is int("1000") False Как это объяснить? Оказывается, интерпретатор “кеширует” объекты int со значениями от -5 до 256, для других значений создаются самостоятельные объекты. Беглый обзор “внутренностей” Python 13
  • 35. int int - тип “малых” целых чисел В Python целые - неизменяемый тип Проверим как на них работает is: >>> int("100") is int("100") True >>> int("1000") is int("1000") False Как это объяснить? Оказывается, интерпретатор “кеширует” объекты int со значениями от -5 до 256, для других значений создаются самостоятельные объекты. Поэтому список intов размером до байта будет иметь overhead в 8 байт на элемент (указатель), а больших intов - до 32 байт на элемент (указатель + объект). Беглый обзор “внутренностей” Python 13
  • 36. int Но загадки на этом не заканчиваются: >>> (1000 is 1000, 1000+0 is 1000+0) (True, False) Беглый обзор “внутренностей” Python 14
  • 37. int Но загадки на этом не заканчиваются: >>> (1000 is 1000, 1000+0 is 1000+0) (True, False) Почему так - немного дальше. Беглый обзор “внутренностей” Python 14
  • 38. string Строки, как и целые, в Python неизменяемы Беглый обзор “внутренностей” Python 15
  • 39. string Строки, как и целые, в Python неизменяемы Однако sharing объектов их затрагивает куда сильнее Беглый обзор “внутренностей” Python 15
  • 40. string Строки, как и целые, в Python неизменяемы Однако sharing объектов их затрагивает куда сильнее Интерпретатор поддерживает dict так называемых interned строк, для каждой из которых гарантированно существует ровно один объект Беглый обзор “внутренностей” Python 15
  • 41. string Строки, как и целые, в Python неизменяемы Однако sharing объектов их затрагивает куда сильнее Интерпретатор поддерживает dict так называемых interned строк, для каждой из которых гарантированно существует ровно один объект Все идентификаторы (имена переменных, модулей, методов), автоматически туда помещаются Беглый обзор “внутренностей” Python 15
  • 42. string Строки, как и целые, в Python неизменяемы Однако sharing объектов их затрагивает куда сильнее Интерпретатор поддерживает dict так называемых interned строк, для каждой из которых гарантированно существует ровно один объект Все идентификаторы (имена переменных, модулей, методов), автоматически туда помещаются Оператор == для interned строк выраждается в is (сравнение указателей) Беглый обзор “внутренностей” Python 15
  • 43. string Строки, как и целые, в Python неизменяемы Однако sharing объектов их затрагивает куда сильнее Интерпретатор поддерживает dict так называемых interned строк, для каждой из которых гарантированно существует ровно один объект Все идентификаторы (имена переменных, модулей, методов), автоматически туда помещаются Оператор == для interned строк выраждается в is (сравнение указателей) Помимо этого, по аналогии с int со значениями [−5, 256] разделяются объекты пустой и всех возможных однобуквенных строк Беглый обзор “внутренностей” Python 15
  • 44. Краткий вывод Не используйте is для чего-то кроме None Беглый обзор “внутренностей” Python 16
  • 45. Краткий вывод Не используйте is для чего-то кроме None Unless you know what you’re doing Беглый обзор “внутренностей” Python 16
  • 47. Виртуальная машина “Железный” процессор не может напрямую выполнять код на C Беглый обзор “внутренностей” Python 18
  • 48. Виртуальная машина “Железный” процессор не может напрямую выполнять код на C Его сначала нужно “разжевать” до очень простых операций, работающих с адресами и регистрами Беглый обзор “внутренностей” Python 18
  • 49. Виртуальная машина “Железный” процессор не может напрямую выполнять код на C Его сначала нужно “разжевать” до очень простых операций, работающих с адресами и регистрами Код на Python также не годится для непосредственного исполнения Беглый обзор “внутренностей” Python 18
  • 50. Виртуальная машина “Железный” процессор не может напрямую выполнять код на C Его сначала нужно “разжевать” до очень простых операций, работающих с адресами и регистрами Код на Python также не годится для непосредственного исполнения Поэтому скрипт при загрузке транслируется в байткод виртуальной машины Беглый обзор “внутренностей” Python 18
  • 51. Виртуальная машина “Железный” процессор не может напрямую выполнять код на C Его сначала нужно “разжевать” до очень простых операций, работающих с адресами и регистрами Код на Python также не годится для непосредственного исполнения Поэтому скрипт при загрузке транслируется в байткод виртуальной машины Виртуальная машина (VM) - это подпрограмма интерпретатора, испоняющая байткод. Беглый обзор “внутренностей” Python 18
  • 52. Виртуальная машина “Железный” процессор не может напрямую выполнять код на C Его сначала нужно “разжевать” до очень простых операций, работающих с адресами и регистрами Код на Python также не годится для непосредственного исполнения Поэтому скрипт при загрузке транслируется в байткод виртуальной машины Виртуальная машина (VM) - это подпрограмма интерпретатора, испоняющая байткод. Но кроме отсутствия “железного” воплощения, концептуальных различий с процессором нет. Беглый обзор “внутренностей” Python 18
  • 53. Байткод Команды CPython VM кодируются одним байтом Беглый обзор “внутренностей” Python 19
  • 54. Байткод Команды CPython VM кодируются одним байтом Каждая из них может иметь опциональный 16-битный аргумент Беглый обзор “внутренностей” Python 19
  • 55. Байткод Команды CPython VM кодируются одним байтом Каждая из них может иметь опциональный 16-битный аргумент Концептуально VM является стековой машиной (уместны аналогии с обратной польской записью и языком Forth) - значения кладутся на value stack (не путать с call stack), операции их снимают с вершины и кладут результат обратно. Беглый обзор “внутренностей” Python 19
  • 56. Байткод Команды CPython VM кодируются одним байтом Каждая из них может иметь опциональный 16-битный аргумент Концептуально VM является стековой машиной (уместны аналогии с обратной польской записью и языком Forth) - значения кладутся на value stack (не путать с call stack), операции их снимают с вершины и кладут результат обратно. При помощи модуля dis можно посмотреть на байткод “живых” функций Беглый обзор “внутренностей” Python 19
  • 57. def f(): a = 1 b = 2 c = 3 return 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_MULTIPLY 28 BINARY_ADD 29 RETURN_VALUE Беглый обзор “внутренностей” Python 20
  • 58. Константы def f(): return (1,"abc", 3.0) Беглый обзор “внутренностей” Python 21
  • 59. Константы def f(): return (1,"abc", 3.0) >>> dis.dis(f) 2 0 LOAD_CONST 4 ((1, ’abc’, 3.0)) 3 RETURN_VALUE Беглый обзор “внутренностей” Python 21
  • 60. Константы 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
  • 61. Code object Как мы видим, байткод это не просто строка байт, так как 16-битных целых недостаточно, чтобы кодировать любые Python-объекты Беглый обзор “внутренностей” Python 22
  • 62. Code object Как мы видим, байткод это не просто строка байт, так как 16-битных целых недостаточно, чтобы кодировать любые Python-объекты Однако их достаточно, чтобы кодировать смещения. Например, в список констант co_consts Беглый обзор “внутренностей” Python 22
  • 63. Code object Как мы видим, байткод это не просто строка байт, так как 16-битных целых недостаточно, чтобы кодировать любые Python-объекты Однако их достаточно, чтобы кодировать смещения. Например, в список констант co_consts Наряду с другой метаинформацией (количество локальных переменных, количество параметров, глубина стека) байткод формирует code object Беглый обзор “внутренностей” Python 22
  • 64. Code object Как мы видим, байткод это не просто строка байт, так как 16-битных целых недостаточно, чтобы кодировать любые Python-объекты Однако их достаточно, чтобы кодировать смещения. Например, в список констант co_consts Наряду с другой метаинформацией (количество локальных переменных, количество параметров, глубина стека) байткод формирует code object Именно code object являет собой единицу существования компилированного кода в Python Беглый обзор “внутренностей” Python 22
  • 65. Code object Как мы видим, байткод это не просто строка байт, так как 16-битных целых недостаточно, чтобы кодировать любые Python-объекты Однако их достаточно, чтобы кодировать смещения. Например, в список констант co_consts Наряду с другой метаинформацией (количество локальных переменных, количество параметров, глубина стека) байткод формирует code object Именно code object являет собой единицу существования компилированного кода в Python Они же сериализуются в .pyc файлы Беглый обзор “внутренностей” Python 22
  • 66. Code object code object являются неизменяемыми Беглый обзор “внутренностей” Python 23
  • 67. Code object code object являются неизменяемыми В “нормальном” коде они строятся единожды - при загрузке модуля Беглый обзор “внутренностей” Python 23
  • 68. Code object code object являются неизменяемыми В “нормальном” коде они строятся единожды - при загрузке модуля Это такой же объект как и все: def f(): def g(): pass return g 2 0 LOAD_CONST 1 (<code object f ...>) 3 MAKE_FUNCTION 0 6 STORE_FAST 0 (f) 3 9 LOAD_GLOBAL 0 (g) 12 RETURN_VALUE Беглый обзор “внутренностей” Python 23
  • 69. Компиляция Процесс преобразования исходного кода модуля в набор code object называется компиляцией Беглый обзор “внутренностей” Python 24
  • 70. Компиляция Процесс преобразования исходного кода модуля в набор code object называется компиляцией Однако компилятор у Python очень рудиментарный - фактически 1-в-1 отображение конструкций в байткод Беглый обзор “внутренностей” Python 24
  • 71. Компиляция Процесс преобразования исходного кода модуля в набор code object называется компиляцией Однако компилятор у Python очень рудиментарный - фактически 1-в-1 отображение конструкций в байткод Оптимизаций уровня байткода почти нет Беглый обзор “внутренностей” Python 24
  • 72. Компиляция Процесс преобразования исходного кода модуля в набор code object называется компиляцией Однако компилятор у Python очень рудиментарный - фактически 1-в-1 отображение конструкций в байткод Оптимизаций уровня байткода почти нет uncompyle, open source декомпилятор Python, способен восстановить исходный код по .pyc файлу почти всегда, потеряв при этом разве что комментарии Беглый обзор “внутренностей” Python 24
  • 73. Компиляция Процесс преобразования исходного кода модуля в набор code object называется компиляцией Однако компилятор у Python очень рудиментарный - фактически 1-в-1 отображение конструкций в байткод Оптимизаций уровня байткода почти нет uncompyle, open source декомпилятор Python, способен восстановить исходный код по .pyc файлу почти всегда, потеряв при этом разве что комментарии Так как компилятор неоптимизирующий, ему почти всегда можно помочь (если надо) Беглый обзор “внутренностей” Python 24
  • 74. Компиляция 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
  • 75. Loop hoisting LOAD_ATTR по идее выполняется небыстро - это поиск строки с именем метода в дикте (хеш-таблице). Строка interned, но все равно это долго. Беглый обзор “внутренностей” Python 26
  • 76. Loop hoisting LOAD_ATTR по идее выполняется небыстро - это поиск строки с именем метода в дикте (хеш-таблице). Строка interned, но все равно это долго. Логично не выполнять эту операцию в теле цикла, а сделать ее единожды до начала выполнения. Беглый обзор “внутренностей” Python 26
  • 77. Loop hoisting LOAD_ATTR по идее выполняется небыстро - это поиск строки с именем метода в дикте (хеш-таблице). Строка interned, но все равно это долго. Логично не выполнять эту операцию в теле цикла, а сделать ее единожды до начала выполнения. Эта оптимизация известна как loop hoisting, но рудиментарный компилятор Python ее не делает. Беглый обзор “внутренностей” Python 26
  • 78. Loop hoisting LOAD_ATTR по идее выполняется небыстро - это поиск строки с именем метода в дикте (хеш-таблице). Строка interned, но все равно это долго. Логично не выполнять эту операцию в теле цикла, а сделать ее единожды до начала выполнения. Эта оптимизация известна как loop hoisting, но рудиментарный компилятор Python ее не делает. Поможем ему! Беглый обзор “внутренностей” Python 26
  • 79. Loop hoisting def f(): l = [] la = l.append for 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
  • 80. LIST_APPEND Добавление к списку - частая операция, и потому в CPython VM есть особый опкод LIST_APPEND Беглый обзор “внутренностей” Python 28
  • 81. 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
  • 83. Дикты и строки Многие знакомые с семантикой Python люди шутят, что Гвидо ван Россум написал dict (открытую хеш-таблицу) и string (неизменяемые строки), после чего решил больше ничего не писать Беглый обзор “внутренностей” Python 30
  • 84. Дикты и строки Многие знакомые с семантикой Python люди шутят, что Гвидо ван Россум написал dict (открытую хеш-таблицу) и string (неизменяемые строки), после чего решил больше ничего не писать Действительно, объекты, модули и неймспейсы - все это обычные дикты cо строковыми ключами Беглый обзор “внутренностей” Python 30
  • 85. Дикты и строки Многие знакомые с семантикой Python люди шутят, что Гвидо ван Россум написал dict (открытую хеш-таблицу) и string (неизменяемые строки), после чего решил больше ничего не писать Действительно, объекты, модули и неймспейсы - все это обычные дикты cо строковыми ключами Глобальное пространство имен модуля, следовательно, тоже дикт, а обращение к переменной - это lookup в дикте. Беглый обзор “внутренностей” Python 30
  • 86. Дикты и строки Многие знакомые с семантикой Python люди шутят, что Гвидо ван Россум написал dict (открытую хеш-таблицу) и string (неизменяемые строки), после чего решил больше ничего не писать Действительно, объекты, модули и неймспейсы - все это обычные дикты cо строковыми ключами Глобальное пространство имен модуля, следовательно, тоже дикт, а обращение к переменной - это lookup в дикте. Всегда ли это так? Беглый обзор “внутренностей” Python 30
  • 87. Дикты и строки def f(): a = 3 return 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_ADD 13 RETURN_VALUE Беглый обзор “внутренностей” Python 31
  • 88. LOAD_FAST и LOAD_GLOBAL 3 6 LOAD_FAST 0 (a) 9 LOAD_GLOBAL 0 (b) Для имен a и b компилятор использовал разные опкоды. Почему? Беглый обзор “внутренностей” Python 32
  • 89. LOAD_FAST и LOAD_GLOBAL 3 6 LOAD_FAST 0 (a) 9 LOAD_GLOBAL 0 (b) Для имен a и b компилятор использовал разные опкоды. Почему? Оказывается, на этапе компиляции в code object собираются все имена локальных переменных (то есть присваиваемые в этом блоке кода и не помеченные явно при помощи global), и заносятся в список co_locals. Беглый обзор “внутренностей” Python 32
  • 90. 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
  • 91. LOAD_FAST и LOAD_GLOBAL LOAD_FAST, как нетрудно догадаться, просто берет значение по индексу из массива Беглый обзор “внутренностей” Python 33
  • 92. LOAD_FAST и LOAD_GLOBAL LOAD_FAST, как нетрудно догадаться, просто берет значение по индексу из массива LOAD_GLOBAL же вынужден брать строку с именем из co_consts, после чего искать по этому ключу в дикте неймспейса Беглый обзор “внутренностей” Python 33
  • 93. LOAD_FAST и LOAD_GLOBAL LOAD_FAST, как нетрудно догадаться, просто берет значение по индексу из массива LOAD_GLOBAL же вынужден брать строку с именем из co_consts, после чего искать по этому ключу в дикте неймспейса Обе операции выполняются с ожидаемой стоимостью O(1), но у массива константа явно лучше Беглый обзор “внутренностей” Python 33
  • 94. LOAD_FAST и LOAD_GLOBAL LOAD_FAST, как нетрудно догадаться, просто берет значение по индексу из массива LOAD_GLOBAL же вынужден брать строку с именем из co_consts, после чего искать по этому ключу в дикте неймспейса Обе операции выполняются с ожидаемой стоимостью O(1), но у массива константа явно лучше Поэтому закешировать что-то в локальную переменную не самая плохая идея в плане производительности Беглый обзор “внутренностей” Python 33
  • 95. Lexical scoping Глобальный и локальный неймспейсы достаточно очевидны сами по себе Беглый обзор “внутренностей” Python 34
  • 96. Lexical scoping Глобальный и локальный неймспейсы достаточно очевидны сами по себе Однако Python позволяет делать вот так: def f(): a = 1 def g(): return a return g >>> t = f() >>> t() 1 Беглый обзор “внутренностей” Python 34
  • 97. Lexical scoping Глобальный и локальный неймспейсы достаточно очевидны сами по себе Однако Python позволяет делать вот так: def f(): a = 1 def g(): return a return g >>> t = f() >>> t() 1 Как возвращенной функции удается вернуть значение из разрушенного фрейма? Беглый обзор “внутренностей” Python 34
  • 98. 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 0 18 STORE_FAST 0 (g) 4 21 LOAD_FAST 0 (g) 24 RETURN_VALUE Беглый обзор “внутренностей” Python 35
  • 99. 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 0 18 STORE_FAST 0 (g) 4 21 LOAD_FAST 0 (g) 24 RETURN_VALUE cell object - это код функции вместе со значениями “внешних” (свободных, free) переменных Беглый обзор “внутренностей” Python 35
  • 100. Lexical scoping cell object по времени жизни не привязан к фрейму, в котором он создан, и собирается сборщиком мусора только тогда, когда станет недостижим. Беглый обзор “внутренностей” Python 36
  • 101. Lexical scoping cell object по времени жизни не привязан к фрейму, в котором он создан, и собирается сборщиком мусора только тогда, когда станет недостижим. Это “взрослая” реализация лексической области видимости Беглый обзор “внутренностей” Python 36
  • 102. Lexical scoping cell object по времени жизни не привязан к фрейму, в котором он создан, и собирается сборщиком мусора только тогда, когда станет недостижим. Это “взрослая” реализация лексической области видимости Однако, к сожалению, она неполна: def f(): a = 1 if True: a = 2; print a print a этот код выведет 2 2. Аналогичный код на C++, или, скажем, Lua, выдаст 2 1 Беглый обзор “внутренностей” Python 36
  • 103. Lexical scoping cell object по времени жизни не привязан к фрейму, в котором он создан, и собирается сборщиком мусора только тогда, когда станет недостижим. Это “взрослая” реализация лексической области видимости Однако, к сожалению, она неполна: def f(): a = 1 if True: a = 2; print a print a этот код выведет 2 2. Аналогичный код на C++, или, скажем, Lua, выдаст 2 1 Это источник трудноуловимых багов Беглый обзор “внутренностей” Python 36
  • 104. Выстрелить в ногу! Что выведет это код? l = [lambda: x for x in "abcdefg"] for r in l: print r(), Беглый обзор “внутренностей” Python 37
  • 105. Выстрелить в ногу! Что выведет это код? l = [lambda: x for x in "abcdefg"] for r in l: print r(), Наверное a b c d e f g? Беглый обзор “внутренностей” Python 37
  • 106. Выстрелить в ногу! Что выведет это код? l = [lambda: x for x in "abcdefg"] for r in l: print r(), Наверное a b c d e f g? Реальность жестока. Беглый обзор “внутренностей” Python 37
  • 107. Выстрелить в ногу! Что выведет это код? 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
  • 108. Lexical scoping К сожалению, различие поведения областей видимости на макро- и микроуровнях настолько глубоко зашито в архитектуре языка, что поправить его практически нереально Беглый обзор “внутренностей” Python 38
  • 109. Lexical scoping К сожалению, различие поведения областей видимости на макро- и микроуровнях настолько глубоко зашито в архитектуре языка, что поправить его практически нереально Даже если это сделать - это с большой вероятностью приведет к “ломанию” имеющегося кода Беглый обзор “внутренностей” Python 38
  • 110. Lexical scoping К сожалению, различие поведения областей видимости на макро- и микроуровнях настолько глубоко зашито в архитектуре языка, что поправить его практически нереально Даже если это сделать - это с большой вероятностью приведет к “ломанию” имеющегося кода Поэтому про данную особенность надо просто помнить, и не сильно увлекаться функциональным программированием на Python ;) Беглый обзор “внутренностей” Python 38
  • 112. Заключение К сожалению, регламент данного доклада не дает слишком разогнаться. За бортом остаются многие интересные темы: Беглый обзор “внутренностей” Python 40
  • 113. Заключение К сожалению, регламент данного доклада не дает слишком разогнаться. За бортом остаются многие интересные темы: Global Interpreter Lock (GIL), или почему программы на Python на нескольких ядрах работают медленнее, чем на одном Беглый обзор “внутренностей” Python 40
  • 114. Заключение К сожалению, регламент данного доклада не дает слишком разогнаться. За бортом остаются многие интересные темы: Global Interpreter Lock (GIL), или почему программы на Python на нескольких ядрах работают медленнее, чем на одном frame object и их список, или как greenlet умудряется эмулировать кооперативную многозадачность “срезанием” стека Беглый обзор “внутренностей” Python 40
  • 115. Заключение К сожалению, регламент данного доклада не дает слишком разогнаться. За бортом остаются многие интересные темы: Global Interpreter Lock (GIL), или почему программы на Python на нескольких ядрах работают медленнее, чем на одном frame object и их список, или как greenlet умудряется эмулировать кооперативную многозадачность “срезанием” стека ООП в Python, или почему у object нельзя выставить атрибут, а у унаследованного от него пустого класса - можно Беглый обзор “внутренностей” Python 40
  • 116. Заключение К сожалению, регламент данного доклада не дает слишком разогнаться. За бортом остаются многие интересные темы: Global Interpreter Lock (GIL), или почему программы на Python на нескольких ядрах работают медленнее, чем на одном frame object и их список, или как greenlet умудряется эмулировать кооперативную многозадачность “срезанием” стека ООП в Python, или почему у object нельзя выставить атрибут, а у унаследованного от него пустого класса - можно Генераторы, или как “шаманство” с фреймами позволяет создавать видимость их (генераторов) наличия, но с серьезными ограничениями Беглый обзор “внутренностей” Python 40
  • 117. Заключение Однако большой проблемы нет - это не сакральное знание Беглый обзор “внутренностей” Python 41
  • 118. Заключение Однако большой проблемы нет - это не сакральное знание Все, что я вам сегодня рассказал, я не прочитал в интернете и на StackOverflow - я прочитал это в исходных кодах интерпретатора Беглый обзор “внутренностей” Python 41
  • 119. Заключение Однако большой проблемы нет - это не сакральное знание Все, что я вам сегодня рассказал, я не прочитал в интернете и на StackOverflow - я прочитал это в исходных кодах интерпретатора Они действительно неплохо структурированы и их довольно просто читать, даже людям без соответствующего бэкграунда Беглый обзор “внутренностей” Python 41
  • 120. Заключение Однако большой проблемы нет - это не сакральное знание Все, что я вам сегодня рассказал, я не прочитал в интернете и на StackOverflow - я прочитал это в исходных кодах интерпретатора Они действительно неплохо структурированы и их довольно просто читать, даже людям без соответствующего бэкграунда Мне это помогло глубже понять как работает тот код, который я пишу, что порой оказывалось очень полезным при профайлинге критичных мест Беглый обзор “внутренностей” Python 41
  • 121. Заключение Однако большой проблемы нет - это не сакральное знание Все, что я вам сегодня рассказал, я не прочитал в интернете и на StackOverflow - я прочитал это в исходных кодах интерпретатора Они действительно неплохо структурированы и их довольно просто читать, даже людям без соответствующего бэкграунда Мне это помогло глубже понять как работает тот код, который я пишу, что порой оказывалось очень полезным при профайлинге критичных мест Это как раз тот случай, когда вместо того, чтобы лезть на StackOverflow, полезнее и интереснее разобраться самому. Так что дерзайте! Беглый обзор “внутренностей” Python 41