Если Python интерпретируется, что такое файлы .pyc?

1084

Мне дали понять, что Python - это интерпретируемый язык ...
Однако, когда я смотрю на свой исходный код Python, я вижу .pycфайлы, которые Windows определяет как «Скомпилированные файлы Python».

Откуда они приходят?

froadie
источник
3
См. Stackoverflow.com/questions/11433579/… для обоснования. Одним словом: скорость.
user7610
Означает ли это, что даже в Python есть «Пиши один раз, беги куда угодно», как в Java?
Мрак Владар
2
@MrakVladar Даже Java - это «Пиши один раз, беги куда угодно [у тебя есть JVM]». Python ничем не отличается; он "запускается везде, где у вас есть виртуальная машина Python". Большая разница в том, что большинство реализаций Python объединяют компилятор и интерпретатор в один исполняемый файл, а не разделяют их как javaи javac.
Чепнер

Ответы:

661

Они содержат байт-код , который является исходным кодом для интерпретатора Python. Этот код затем выполняется виртуальной машиной Python.

Документация Python объясняет определение следующим образом:

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

размотать
источник
10
Интересно, спасибо. Так считается ли Python чисто интерпретируемым языком?
Froadie
194
@froadie: язык не «интерпретируется» и не «компилируется» как таковой. Конкретная реализация может быть переводчиком или компилятор (или гибрид или JIT - компилятор).
Иоахим Зауэр
30
Один тест «скомпилировано»: скомпилировано ли оно с фактическими инструкциями машины? Байт-код Python не является машинными инструкциями и не является Java-инструкцией JVM, поэтому ни один из этих языков не скомпилирован по этому определению. Но оба «скомпилированы» в промежуточный код «абстрактной машины», и оба намного, быстрее, чем запускают программу, более или менее напрямую интерпретируя исходный код (что и делает BASIC старой школы).
Грегго
20
Чтобы быть педантичным, «скомпилированный» означает «переведенный». Затем Python компилируется в байт-код. AFAIK, только Bash действительно интерпретируется, все другие популярные "интерпретируемые" языки все скомпилированы в байт-код.
bfontaine
13
На самом деле, они являются машинными инструкциями, а не нативными машинными инструкциями для физического процессора хоста. Следовательно, почему мы называем это VM? Как эсперанто для ассемблера. В настоящее время у нас даже есть собственный код для вымышленных (но все еще эмулируемых) процессоров (попытка Mojang заинтересовать детишек). Rexx был (или мог быть) действительно интерпретирован, а BAT и CMD (и DCL) интерпретированы.
mckenzm
995

Мне дали понять, что Python - это интерпретируемый язык ...

Этот популярный мем некорректен, или, скорее, построен на неправильном понимании (естественного) уровня языка: похожая ошибка - сказать «Библия - книга в твердом переплете». Позвольте мне объяснить это сравнение ...

«Библия» - это «книга» в том смысле, что она представляет собой класс (реальных физических объектов, идентифицированных как) книг; Предполагается, что книги, обозначенные как «копии Библии», имеют что-то общее (содержание, хотя даже они могут быть на разных языках, с разными приемлемыми переводами, уровнями сносок и другими аннотациями), однако эти книги вполне допустимо отличаться множеством аспектов, которые не считаются фундаментальными - вид переплета, цвет переплета, шрифт (ы), используемые при печати, иллюстрации, если таковые имеются, широкие поля для записи или нет, числа и виды встроенных закладок , и так далее и тому подобное.

Вполне возможно, что типичная печать Библии действительно была бы в переплете в твердом переплете - в конце концов, это книга, которую обычно нужно читать снова и снова, делать закладки в нескольких местах, пролистывать в поисках данных указателей на главы и стихи и т. д., и т. д., и хорошее связывание в твердом переплете может продлить срок действия данной копии при таком использовании. Однако это обычные (практические) вопросы, которые нельзя использовать для определения того, является ли данный фактический объект книги копией Библии или нет: печатные издания в мягкой обложке вполне возможны!

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

Классическая реализация, CPython, часто для краткости называется просто «Python» - но это всего лишь одна из нескольких реализаций производственного качества, наряду с Microsoft IronPython (который компилируется в коды CLR, т. Е. «.NET»), Jython (который компилируется в коды JVM), PyPy (который написан на самом Python и может компилироваться в огромное разнообразие «внутренних» форм, включая машинный язык, генерируемый «точно в срок»). Все они - Python (== "реализации языка Python"), точно так же, как многие поверхностно разные книжные объекты могут быть Библиями (== "копии Библии").

Если вы особенно заинтересованы в CPython: он компилирует исходные файлы в специфичную для Python форму нижнего уровня (известную как «байт-код»), делает это автоматически при необходимости (когда нет файла байт-кода, соответствующего исходному файлу, или файл байт-кода старше исходного или скомпилирован другой версией Python), обычно сохраняет файлы байт-кода на диск (чтобы не перекомпилировать их в будущем). OTOH IronPython обычно компилируется в коды CLR (сохраняя их на диск или нет, в зависимости от) и Jython в коды JVM (сохраняя их на диск или нет - он будет использовать .classрасширение, если сохранит их).

Эти формы более низкого уровня затем выполняются соответствующими «виртуальными машинами», также известными как «интерпретаторы» - виртуальная машина CPython, среда выполнения .Net, виртуальная машина Java (также известная как JVM), в зависимости от ситуации.

Таким образом, в этом смысле (что делают типичные реализации), Python является «интерпретируемым языком» тогда и только тогда, когда есть C # и Java: у всех них есть типичная стратегия реализации, которая сначала создает байт-код, а затем выполняет его через VM / интерпретатор. ,

Скорее всего, основное внимание уделяется тому, насколько «тяжелым», медленным и запоминающимся является процесс компиляции. CPython предназначен для компиляции настолько быстро, насколько это возможно, настолько легко, насколько это возможно, с минимально возможной церемонией - компилятор выполняет очень мало проверки и оптимизации ошибок, поэтому он может работать быстро и с небольшими объемами памяти, что, в свою очередь, позволяет ему запускаться автоматически и прозрачно при необходимости, даже если пользователю не нужно знать, что в большинстве случаев происходит компиляция. Java и C # обычно принимают больше работы во время компиляции (и поэтому не выполняют автоматическую компиляцию), чтобы более тщательно проверять ошибки и выполнять больше оптимизаций. Это континуум серых шкал, а не черная или белая ситуация,

Алекс Мартелли
источник
2
Прекрасный ответ. Небольшое исправление к последнему абзацу: Python предназначен для максимально быстрой компиляции (и т. Д.). На этот раз это действительно язык с отсутствием статической системы типов и тому подобного. Когда люди говорят о «интерпретируемых» языках, они обычно имеют в виду «динамические» языки.
Элазар
2
@Elazar, на самом деле, другие реализации Python, такие как PyPy, которые не спешат компилировать, могут выполнять более тщательный анализ, необходимый из-за отсутствия статической типизации, и производить своевременную компиляцию в машинный код (таким образом, ускоряя многократно запущенные программы).
Алекс Мартелли
Где Cython вписывается здесь? Считаете ли вы это другим языком или это реализация Python? Кроме того, является ли этот мем «интерпретированной» против скомпилированной, возможно, просто путаницей в терминологии, поскольку виртуальную машину Python часто называют ее «интерпретатором»? Было бы так же правильно вызывать JVM или .NET-интерпретаторы времени выполнения. Оба они в основном интерпретируют байт-код в машинный код JIT (с некоторыми исключениями оптимизации кэширования)
Давос,
181

Там нет такой вещи, как интерпретируемый язык. Независимо от того, используется ли интерпретатор или компилятор, это особенность реализации и не имеет абсолютно никакого отношения к языку.

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

Язык - это просто набор абстрактных математических правил. Интерпретатор - это одна из нескольких конкретных стратегий реализации языка. Эти двое живут на совершенно разных уровнях абстракции. Если бы английский был типизированным языком, термин «интерпретируемый язык» был бы ошибкой типа. Утверждение «Python - это интерпретируемый язык» - это не просто ложь (поскольку ложь подразумевает, что это утверждение даже имеет смысл, даже если оно неверно), оно просто не имеет смысла , поскольку язык никогда не может быть определен как «интерпретированы.»

В частности, если вы посмотрите на существующие в настоящее время реализации Python, это стратегии реализации, которые они используют:

  • IronPython: компилируется в деревья DLR, которые затем компилируется в байт-код CIL. Что происходит с байт-кодом CIL, зависит от того, на каком CLI VES вы работаете, но Microsoft .NET, GNU Portable.NET и Novell Mono со временем скомпилируют его в машинный код.
  • Jython: интерпретирует исходный код Python до тех пор, пока он не идентифицирует пути горячего кода, который затем компилируется в байт-код JVML. Что происходит с байт-кодом JVML, зависит от того, на какой JVM вы работаете. Maxine напрямую скомпилирует его в неоптимизированный нативный код, пока не определит пути горячего кода, которые затем перекомпилирует в оптимизированный нативный код. HotSpot сначала интерпретирует байт-код JVML, а затем в конечном итоге компилирует пути горячего кода в оптимизированный машинный код.
  • PyPy: компилируется в байт-код PyPy, который затем интерпретируется виртуальной машиной PyPy до тех пор, пока он не идентифицирует пути горячего кода, которые затем компилируется в собственный код, байт-код JVML или байт-код CIL, в зависимости от платформы, на которой вы работаете.
  • CPython: компилируется в байт-код CPython, который затем интерпретируется.
  • Stackless Python: компилируется в байт-код CPython, который затем интерпретируется.
  • Разгрузить Swallow: компилируется в байт-код CPython, который затем интерпретируется, пока не будет идентифицирован путь горячего кода, который затем компилируется в IR LLVM, который компилятор LLVM затем компилирует в собственный машинный код.
  • Cython: компилирует код Python в переносимый код C, который затем компилируется стандартным компилятором C
  • Nuitka: компилирует код Python в машинно-зависимый код C ++, который затем компилируется стандартным компилятором C

Вы можете заметить, что у каждой из реализаций в этом списке (плюс некоторые другие, которые я не упомянул, например, tinypy, Shedskin или Psyco) есть компилятор. На самом деле, насколько я знаю, в настоящее время нет реализации Python, которая является чисто интерпретируемой, такой реализации не планируется и такой реализации никогда не было.

Термин «интерпретируемый язык» не только не имеет смысла, даже если вы интерпретируете его как «язык с интерпретируемой реализацией», он явно не соответствует действительности. Кто бы вам ни говорил, очевидно, не знает, о чем говорит.

В частности, .pycфайлы, которые вы видите, являются кэшированными файлами байт-кода, созданными CPython, Stackless Python или Unladen Swallow.

Йорг Миттаг
источник
6
Основы старой школы, такие как MSBASIC, не имели промежуточной формы. Программа интерпретировалась непосредственно из исходной формы (или около источника, формы, в которой ключевые слова были представлены 1-байтовыми токенами, а строки # - 2-байтовыми двоичными числами, но остальное было просто ASCII). Таким образом, на самом деле «goto» занимало бы различное количество времени в зависимости от того, сколько строк исходного текста ему пришлось искать в поисках подходящего пункта назначения. Такие выражения, как a * b-2 * cos (x), эффективно анализировались каждый раз при их выполнении.
Грегго
4
@greggo: И если вы хотите пойти еще дальше, то оригинальной версией BASIC был компилятор нативного кода. Это должно доказать, насколько нелепым является понятие «скомпилированного» или «интерпретируемого» языка.
Йорг Миттаг
Спасибо за объяснение того, как ведут себя различные компиляторы / интерпретаторы python. Интересно, есть ли хорошие компиляторы Python, которые еще генерируют эффективный C или JavaScript? Это кажется очень выполнимым, возможно, не для массового потребления, но для разумного подмножества Python, по крайней мере. Также мне интересно, что такое Cython.
personal_cloud
Cython упоминался в SciPy 2009, но я могу простить вас за то, что вы не знали об этом еще в 2010 году (здесь я в 2017 году, только сейчас узнаю об этом). Тем не менее, мы должны найти пример JavaScript ... Jython не имеет для меня никакого смысла (разве Java уже не умерла к 2009 году? Ну, может, нет ... Повышение C ++ тогда было не очень хорошим)
personal_cloud
1
@personal_cloud: Я не совсем понимаю ваш комментарий. Да, конечно, я знаю о Cython, но какое это имеет отношение к чему-либо? Это не реализация Python, это совершенно другой язык. Кроме того, действительно нетрудно найти пример JavaScript, на самом деле, все существующие в настоящее время основные реализации JavaScript имеют компиляторы. Наконец, Jython - это реализация Python, как и любая другая реализация Python. И это реализация языка на платформе Java, как и любая другая реализация языка на платформе Java.
Йорг Миттаг
61

Они создаются интерпретатором Python при .pyимпорте файла и содержат «скомпилированный байт-код» импортированного модуля / программы, идея в том, что «перевод» из исходного кода в байт-код (который необходимо выполнить только один раз) может быть пропущен при последующих imports, если .pycон новее соответствующего .pyфайла, что немного ускоряет запуск. Но это все еще интерпретируется.

Тим Питцкер
источник
10
Правда. За исключением многих основных библиотек Python, написанных на C. Поэтому части Python выполняются интерпретируемыми, а часть - на C. Вы можете сделать то же самое для своих собственных чувствительных к производительности битов кода.
bwawok
44

Чтобы ускорить загрузку модулей, Python кэширует скомпилированное содержимое модулей в .pyc.

CPython компилирует свой исходный код в «байтовый код» и по соображениям производительности кэширует этот байтовый код в файловой системе всякий раз, когда в исходном файле есть изменения. Это значительно ускоряет загрузку модулей Python, потому что этап компиляции можно обойти. Если исходный файл - foo.py, CPython кэширует байт-код в файле foo.pyc рядом с исходным кодом.

В python3 механизм импорта Python расширен для записи и поиска файлов кэша байтового кода в одном каталоге внутри каждого каталога пакета Python. Этот каталог будет называться __pycache__.

Вот блок-схема, описывающая, как загружаются модули:

введите описание изображения здесь

За дополнительной информацией:

ref: PEP3147
ref: «скомпилированные» файлы Python

hxysayhi
источник
38

ЭТО ДЛЯ НАЧИНАЮЩИХ,

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

Запуск сценария не считается импортом, и .pyc не будет создан.

Например, если у вас есть файл сценария abc.py , который импортирует другой модуль xyz.py , при запуске abc.py , xyz.pyc будет создан , так как хуг импортируется, но не abc.pyc файл не будет создан , поскольку аЬс. py не импортируется.

Если вам необходимо создать .pyc файл для модуля , который не импортируется, вы можете использовать py_compileи compileallмодули.

py_compileМодуль может вручную компилировать любой модуль. Одним из способов является использование py_compile.compileфункции в этом модуле в интерактивном режиме:

>>> import py_compile
>>> py_compile.compile('abc.py')

Это запишет .pyc в то же место, что и abc.py (вы можете переопределить его с помощью необязательного параметра cfile).

Вы также можете автоматически скомпилировать все файлы в каталоге или каталогах, используя модуль compileall.

python -m compileall

Если имя каталога (текущий каталог в этом примере) опущено, модуль компилирует все найденное на sys.path

МАКСИМУМ
источник
6
и какая польза от компиляции для получения abc.py?
Сахер Ахвал
@SaherAhwal Одно из преимуществ, которое я могу придумать, - это проверка синтаксиса.
И Бао
20

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

Другая сторона этого, однако, в том, что процесс компиляции в основном скрыт - файлы .pyc в основном обрабатываются как кеш; они ускоряют процесс, но обычно вам не нужно о них вообще знать. Он автоматически делает недействительными и перезагружает их (перекомпилирует исходный код), когда это необходимо, на основании отметок времени / даты файла.

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

Джерри Гроб
источник
12

Файл * .py Python - это просто текстовый файл, в котором вы пишете несколько строк кода. Когда вы пытаетесь выполнить этот файл, используя «python filename.py»

Эта команда вызывает виртуальную машину Python. Виртуальная машина Python имеет 2 компонента: «компилятор» и «интерпретатор». Интерпретатор не может напрямую читать текст в файле * .py, поэтому этот текст сначала преобразуется в байтовый код, предназначенный для PVM (не аппаратного, а PVM) . PVM выполняет этот байт-код. Файл * .pyc также генерируется, как часть его запуска, который выполняет операцию импорта для файла в оболочке или в каком-либо другом файле.

Если этот * .pyc-файл уже создан, то каждый раз, когда вы запускаете / запускаете ваш * .py-файл, система напрямую загружает ваш * .pyc-файл, который не требует компиляции (это сэкономит вам некоторые машинные циклы процессора).

После создания файла * .pyc файл * .py не требуется, если вы его не редактируете.

Вишал Мопари
источник
7

Код Python проходит 2 этапа. Первый шаг компилирует код в файлы .pyc, который на самом деле является байт-кодом. Затем этот файл .pyc (байт-код) интерпретируется с использованием интерпретатора CPython. Пожалуйста, обратитесь к этой ссылке. Здесь процесс компиляции и выполнения кода объясняется в простых терминах.

Танго
источник