Отличия между .pyc, .pyd и .pyo файлами
В этой статье будут рассмотрены Python типы файлов .pyc, .pyd и .pyo, предназначенные для хранения байт-кода, который будет импортирован другими Python программами.
Все кто когда-либо писал программы на Python уже встречались с .py файлами, но будет не менее интересно узнать, какую роль играют эти и другие типы файлов и где они находят своё применение. Чтобы понять это, будет рассмотрено преобразование кода на Python в инструкции, которые напрямую может выполнить компьютер.
Байт-код и виртуальная машина Python
Python поставляется с интерпретатором, который может использоваться в качестве REPL (цикл «чтение — вычисление — вывод»), в интерактивном режиме и в командной строке. Кроме того, можно вызвать Python со скриптами кода Python. В обоих случаях интерпретатор анализирует получаемый файл, а затем компилируется его в байт-код (низкий уровень машинных инструкций), которое затем выполняется с помощью виртуальной машины Python.
Однако он отличается от других виртуальных машин, таких как виртуальная машина Java или виртуальная машина Erlang, поэтому заслуживает самостоятельного рассмотрения. Виртуальная машина, в свою очередь, взаимодействует с операционной системой и реальным оборудованием для выполнения машинных инструкций.
Важная вещь, о которой следует помнить, что файлы типа .pyc, .pyo и .pyd, создаются интерпретатором Python, когда он преобразует человекочитаемый код в скомпилированный байт-код. Компиляция Python скрипта в байт-код является необходимым промежуточным шагом в процессе перевода инструкций из исходного кода на удобочитаемом языке в машинные инструкции, которые потом выполняет операционная система.
.pyc файлы
Файлы типа .pyc автоматически генерируются интерпретатором при импорте модуля, что ускоряет следующие импорты этого модуля. Поэтому такие файлы создаются только из .py файлов, если они импортируется другим .py файлом или модулем.
Пример модуля Python, который потом будет импортирован. Данный модуль вычисляет факториал числа.
# math_helpers.py
# функция вычисления факториала числа
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n - 1)
def main():
# печать результата
print(factorial(5))
if __name__ == '__main__':
main()
Теперь, если запустить модуль из командной строки, используя python math_helpers.py, файл .pyc создан не будет.
Теперь импортируем его в другом модуле, как показано ниже.
# computations.py
from math_helpers import factorial
def main():
print(factorial(6))
if __name__ == '__main__':
main()
Производится импорт factorial функции из файла math_helpers.py и вызов её для вычисления факториала 6.
Запустим скрипт, вызвав python computations.py в терминале. В результате получаем не только факториал 6 (6!=720), но также замечаем, что интерпретатор автоматически создал файл math_helpers.pyc. Это происходит потому, что основной модуль импортирует math_helpers. Чтобы ускорить загрузку импортированного модуля в будущем, интерпретатор создает файл байт-кода модуля.
Когда обновляется файл исходного кода, также обновляется и файл .pyc. Это происходит всякий раз, когда время обновления исходного кода отличается от времени файла байт-кода и это гарантирует обновление байт-кода.
Обратите внимание: использование файлов .pyc только ускоряет загрузку программы, а не её выполнение. Это означает, что можно улучшить время запуска, написав основную программу модулем, который импортируется другим, меньшим модулем. Однако для повышения производительности в целом необходимо изучить такие методы, как оптимизация алгоритмов и алгоритмический анализ.
Поскольку .pyc-файлы независимы от платформы, они могут быть распределены между компьютерами разных архитектур. Однако, если разработчики работают в разных часовых поясах, коммит .pyc файлов в CVS может создавать временные метки в будущем. Таким образом, обновления исходного кода больше не вызывают изменения в байт-коде. Это может породить неприятные ошибки. Лучший способ избежать этого – добавить файлы .pyc в список игнорирования в системе управления версиями (.gitignore).
Файлы .pyo
Файлы .pyo также создается интерпретатором при импорте модуля, но с указанием интерпретатору включения параметров оптимизации.
Оптимизатор активируется добавлением флага «-O» при вызове интерпретатора Python. Пример кода, иллюстрирующий использование оптимизации. Во-первых, у нас есть модуль, который определяет лямбду. В Python лямбда подобна функции, но определяется более кратко.
# lambdas.py
# лямбда создаёт функцию умножения x на 2
g = lambda x: x * 2
В следующем коде импортируем lambdas.py и вызовем g lambda.
# using_lambdas.py
import lambdas
print(lambdas.g(7))
Теперь перейдём к важной части этого примера. Вместо обычного вызова Python, как в последнем примере, мы будем использовать оптимизацию. Если включить оптимизатор, создаются более компактные файлы байт-кода, чем без использования оптимизатора.
Чтобы запустить пример с помощью оптимизатора, вызовем команду:
$ python -O using_lambdas.py
Мы не только получаем правильный результат удвоения 7 (14), как вывод в командной строке, но также видим, что для нас автоматически создается новый файл байткода. Этот файл основан на файле lambdas.py в вызове using_lambdas.py. Поскольку у нас включен оптимизатор, создается файл байт-кода .pyo. В нашем случае он называется lambdas.pyo.
Оптимизатор удаляет операторы assert из байт-кода и всё... В большинстве случаев результат не будет заметным, но могут быть случаи, когда это может быть полезно.
Также обратите внимание, файл байт-кода .pyo заменяет файл .pyc, который был бы создан без оптимизации. Файл .pyo обновляется всякий раз, когда время обновления исходного кода отличается от времени файла байт-кода.
Тип файла .pyd
Тип файла .pyd, в отличие от предыдущих двух, предназначен только для семейства ОС Windows. Таким образом он может встретиться в дистрибутивах установленных программ в персональных и корпоративных версиях Windows 10, 8, 7 и других.
В экосистеме Windows файл .pyd представляет собой файл библиотеки, содержащий код Python, который может быть вызван и использован другими приложениями Python. Чтобы сделать эту библиотеку доступной для других программ Python, она упакована в виде динамически подключаемой библиотеки.
Динамически подключаемые библиотеки (DLL) – это библиотеки скомпилированного кода Windows, которые подключаются к вызывающей её программе во время выполнения. Основным преимуществом таких библиотек как DLL, является то, что они облегчают повторное использование кода, позволяют строить модульные архитектуры и ускоряют запуск программ. В результате библиотеки DLL обеспечивают большую функциональность в ОС Windows.
Файлы .pyd – это dll, но есть несколько отличий. Если есть DLL файл с именем hello.pyd, он должен содержать функцию inithello() как точку входа. Затем можно написать в Python «import hello», и интерпретатор будет искать hello.pyd (а также hello.py, hello.pyc), и если он найдет его, попытается вызвать inithello() для его инициализации.
Обратите внимание, что путь поиска для hello.pyd – это PYTHONPATH и это не тот путь, который использует Windows для поиска hello.dll.
Различия между типами файлов
Хотя между этими типами файлов существует некоторое сходство, есть также и некоторые значительные различия. Например, файлы .pyc и .pyo во многом аналогичны, поскольку они содержат байт-код Python, отличие же заключается в том, что файлы .pyo более компактны, благодаря оптимизации, сделанной интерпретатором.
Третий тип файла .pyd отличается от предыдущих двух тем, что является DLL, которая будет использоваться в ОС Windows. Остальные два типа файлов могут использоваться в любой операционной системе, а не только в Windows.
Вывод
В этой статье было рассказано о специальных типах файлов .pyc, .pyo и .pyd используемых виртуальной машиной Python для повторного использования кода. Каждый файл, как мы видели, имеет своё особое назначение и варианты использования, будь то ускорение загрузки модуля, ускорение выполнения или облегчение повторного использования кода.