Python интерпретируется или компилируется, или и то, и другое?

Из моего понимания:

Интерпретируемый язык - это язык высокого уровня, запускаемый и выполняемый интерпретатором (программой, которая преобразует язык высокого уровня в машинный код и затем выполняет) на ходу; он обрабатывает программу постепенно.

Скомпилированный язык - это язык высокого уровня, код которого сначала преобразуется в машинный код компилятором (программа, которая преобразует язык высокого уровня в машинный код), а затем исполняется исполнителем (другая программа для запуска кода).

Поправь меня, если мои определения неверны.

Возвращаясь к Python, я немного запутался по этому поводу. Везде вы узнаете, что Python - это интерпретируемый язык, но он интерпретируется как некоторый промежуточный код (например, байт-код или IL), а не как машинный код. Так, какая программа тогда выполняет код IM? Пожалуйста, помогите мне понять, как обрабатывается и выполняется скрипт Python.

15 ответов

Решение

Во-первых, интерпретация / компиляция - это не свойство языка, а свойство реализации. Для большинства языков большинство, если не все реализации, попадают в одну категорию, поэтому можно было бы сохранить несколько слов, говоря, что язык также интерпретируется / компилируется, но это по-прежнему важное различие, как потому, что оно помогает пониманию, так и потому, что существует довольно много языков. с применимыми реализациями обоих видов (в основном в области функциональных языков, см. Haskell и ML). Кроме того, существуют интерпретаторы C и проекты, которые пытаются скомпилировать подмножество Python для кода C или C++ (и впоследствии для машинного кода).

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

Но чтобы перестать придираться и ответить на вопрос, который вы хотели задать: на практике (читай: используя несколько популярную и зрелую реализацию), Python компилируется. Не скомпилирован в машинный код досрочно (то есть "скомпилирован" по ограниченному и неправильному, но, увы, общему определению), "только" скомпилирован в байт-код, но он все еще компилируется с некоторыми из преимуществ Например, заявление a = b.c() компилируется в поток байтов, который при "разборке" выглядит как load 0 (b); load_str 'c'; get_attr; call_function 0; store 1 (a), Это упрощение, оно на самом деле менее читаемо и немного более низкоуровневое - вы можете поэкспериментировать со стандартной библиотекой dis модуль и посмотреть, как выглядит реальная сделка. Интерпретация это быстрее, чем интерпретация из представления более высокого уровня.

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

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

Интерпретатор Python сначала читает человеческий код и оптимизирует его до некоторого непосредственного кода, прежде чем интерпретировать его в машинный код. Вот почему вам всегда нужна другая программа для запуска скрипта Python, в отличие от C++, вы можете запустить исполняемый файл напрямую. Например, c:\Python27\python.exe или /usr/bin/python.

Ответ зависит от того, какая реализация Python используется. Если вы используете, скажем, CPython (стандартная реализация python) или Jython (предназначенный для интеграции с языком программирования Java), он сначала переводится в байт-код, и в зависимости от используемой вами реализации python, этот код направляется в соответствующий виртуальная машина для интерпретации. PVM (виртуальная машина Python) для CPython и JVM (виртуальная машина Java) для Jython.

Но допустим, вы используете PyPy, которая является еще одной стандартной реализацией CPython. Он будет использовать компилятор Just-In-Time.

Да, это и компилируемый, и интерпретируемый язык. Тогда почему мы обычно называем его интерпретируемым языком?

посмотреть, как он компилируется и интерпретируется?

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

В Java исходный код сначала преобразуется в байтовый код с помощью компилятора javac, а затем направляется в JVM(отвечающую за создание собственного кода для выполнения). Теперь я хочу показать вам, что мы называем Java компилируемым языком, потому что мы видим, что он действительно компилирует исходный код и передает файл .class (только байт-код) через:

javac Hello.java -------> создает файл Hello.class

java Hello --------> Направление байт-кода в JVM для выполнения

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

python Hello.py -------> непосредственно запускает код, и мы можем видеть результат, доказывающий, что код синтаксически правильный

@ python Hello.py похоже, что он выполняется напрямую, но на самом деле он сначала генерирует байт-код, который интерпретируется интерпретатором для создания собственного кода для цели выполнения.

CPython- берет на себя ответственность как за компиляцию, так и за интерпретацию.

Если вам нужна дополнительная информация, посмотрите следующие строки:

Как я уже упоминал, CPython компилирует исходный код, но фактическая компиляция происходит с помощью cython, тогда интерпретация происходит с помощью CPython.

Теперь поговорим немного о роли компилятора Just-In-Time в Java и Python.

В JVM существует Java Interpreter, который интерпретирует байт-код построчно, чтобы получить собственный машинный код для выполнения, но когда байт-код Java выполняется интерпретатором, выполнение всегда будет медленнее. Так какое же решение? решение - это компилятор Just-In-Time, который производит собственный код, который может быть выполнен намного быстрее, чем его можно было бы интерпретировать. Некоторые поставщики JVM используют Java Interpreter, а некоторые используют компилятор Just-In-Time. Ссылка: нажмите здесь

В Python, чтобы обойти интерпретатор и добиться быстрого выполнения, используйте другую реализацию Python (PyPy) вместо CPython.щелкните здесь, чтобы увидеть другую реализацию python, включая PyPy.

Согласно python.org это переводчик.

https://www.python.org/doc/essays/blurb/

Python - это интерпретируемый объектно-ориентированный язык программирования высокого уровня...

...

Поскольку нет этапа компиляции...

...

Доступен интерпретатор Python и обширная стандартная библиотека...

...

Вместо этого, когда интерпретатор обнаруживает ошибку, он вызывает исключение. Когда программа не перехватывает исключение, интерпретатор печатает трассировку стека.

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

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

  • Он скомпилирован в байт-код.
  • Затем он направляется на виртуальную машину.

Когда мы выполняем исходный код, Python компилирует его в байтовый код. Компиляция - это этап трансляции, а байт-код - это низкоуровневое платформо-независимое представление исходного кода. Обратите внимание, что байт-код Python не является двоичным машинным кодом (например, инструкциями для микросхемы Intel).

Фактически, Python переводит каждую инструкцию исходного кода в инструкции байтового кода, разбивая их на отдельные шаги. Трансляция байт-кода выполняется для ускорения выполнения. Байт-код может выполняться намного быстрее, чем исходные операторы исходного кода. У него есть расширение.pyc, и оно будет записано, если сможет писать на нашу машину.

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

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

Подведем итог тому, что происходит за кадром. Когда Python выполняет программу, Python считывает файл.py в память и анализирует его, чтобы получить байт-код, а затем продолжает выполнение. Для каждого модуля, импортируемого программой, Python сначала проверяет, есть ли предварительно скомпилированная версия байт-кода в.pyo или.pyc, имеющая метку времени, соответствующую его файлу.py. Python использует версию байт-кода, если таковая имеется. В противном случае он анализирует файл.py модуля, сохраняет его в файл.pyc и использует только что созданный байт-код.

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

Виртуальная машина Python (PVM)

После того, как наша программа была скомпилирована в байт-код, она отправляется для выполнения на виртуальную машину Python (PVM). PVM - это не отдельная программа. Его не нужно устанавливать отдельно. Фактически, PVM - это просто большой цикл, который выполняет итерацию по нашей инструкции байтового кода, одну за другой, для выполнения своих операций. PVM - это среда выполнения Python. Он всегда присутствует как часть системы Python. Это компонент, который действительно запускает наши скрипты. Технически это просто последний шаг того, что называется интерпретатором Python.

Если (Вы знаете Java) {

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

} еще {

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

}

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

И этот байт-код выполняется каждый раз, когда вы запускаете программу. Как? Что ж, когда мы запускаем программу, этот байт-код (внутри файла.pyc) передается в качестве входных данных на виртуальную машину (ВМ)1 - механизм времени выполнения, позволяющий выполнять наши программы, - которая его выполняет.

В зависимости от языковой реализации виртуальная машина будет либо интерпретировать байт-код (в случае реализации CPython2), либо JIT-компилировать3 его (в случае реализации PyPy4).

Примечания:

1 эмуляция компьютерной системы

2 интерпретатор байт-кода; эталонная реализация языка, написанная на C и Python - наиболее широко используемая

3 компиляция, которая выполняется во время выполнения программы (во время выполнения)

4 JIT-компилятор байт-кода; альтернативная реализация CPython, написанная на RPython (Restricted Python) - часто работает быстрее, чем CPython

Для новичков

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

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

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

Скомпилирован Python(интерпретатор) .

Доказательство: он даже не скомпилирует ваш код, если он содержит синтаксическую ошибку.

Пример 1:

print("This should print") 
a = 9/0 

Выход:

This should print
Traceback (most recent call last):
  File "p.py", line 2, in <module>
    a = 9/0
ZeroDivisionError: integer division or modulo by zero

Код успешно компилируется. Выполняется первая строка (print) вторая строка бросает ZeroDivisionError (ошибка выполнения) .

Пример 2:

print("This should not print")
/0         

Выход:

  File "p.py", line 2
    /0
    ^
SyntaxError: invalid syntax

Вывод: если ваш файл кода содержитSyntaxError ничего не будет выполнено, поскольку компиляция не удалась.

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

Как уже было сказано, «интерпретируемый / скомпилированный - это не свойство языка, а свойство реализации». Python можно использовать как в режиме интерпретации, так и в режиме компиляции. Когда вы запускаете код Python непосредственно из терминала или cmd, запускается интерпретатор Python. Теперь, если вы напишете любую команду, эта команда будет напрямую интерпретироваться. Если вы используете файл, содержащий код Python, и запускаете его в среде IDE или с помощью командной строки, он сначала будет скомпилирован, весь код будет преобразован в байтовый код, а затем он будет запущен. Так что это зависит от того, как мы его используем.

Код Python, который вы пишете, компилируется в байт-код Python, который создает файл с расширением.pyc. Если компилируется, опять вопрос, почему не компилируется язык.

Обратите внимание, что это не компиляция в традиционном смысле этого слова. Как правило, мы бы сказали, что компиляция использует язык высокого уровня и преобразует его в машинный код. Но это сборник сортов. Скомпилирован в промежуточный код, а не в машинный код (надеюсь, вы получили его сейчас).

Возвращаясь к процессу выполнения, ваш байт-код, присутствующий в pyc-файле, созданный на этапе компиляции, затем выполняется соответствующими виртуальными машинами, в нашем случае - виртуальной машиной CPython. Отметка времени (называемая магическим числом) используется для проверки того, действительно ли. Файл py изменяется или нет, в зависимости от того, что новый файл pyc создан. Если pyc имеет текущий код, то он просто пропускает этап компиляции.

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

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

Я считаю, что наличие промежуточного кода (например, байт-кода) не имеет значения, чтобы отнести его к категории компилятора. Хотя этот компонент (генерация промежуточного кода) обычно является частью компилятора, его также можно использовать в интерпретаторах. См. Вики-определение интерпретатора https://en.m.wikipedia.org/wiki/Interpreter_(computing) . Это критически важный элемент для повышения эффективности с точки зрения скорости выполнения. С кешем он еще более мощный, так что, если вы не изменили код в текущем объеме программы, вы пропустите тяжелые этапы обработки, такие как лексический, семантический анализ и даже некоторые оптимизации кода.

Другие вопросы по тегам