Чем отличается интерпретатор от компилятора и почему
Что проверяют
Понимаете ли вы, что происходит с вашим кодом между запуском файла и выполнением, и не считаете ли Python языком, который просто читает строчки сверху вниз. Дальше обычно идут вопросы про байткод, кэш в __pycache__ и про то, почему Python медленнее компилируемых языков.
Как отвечать
Компилятор переводит исходник в другое представление заранее, интерпретатор исполняет представление по шагам. Ключевое уточнение: это свойство реализации, а не языка, и в большинстве живых языков присутствуют обе стадии.
CPython работает так: исходник целиком разбирается в дерево, дерево компилируется в байткод, байткод сохраняется рядом файлом .pyc, и дальше виртуальная машина выполняет его инструкции. То есть Python компилируется, просто не в машинный код, а в инструкции собственной машины.
import dis
def f(x):
return x + 1
dis.dis(f)Отсюда честные различия. Компиляция в машинный код заранее даёт скорость и раннюю проверку типов, но требует сборки под платформу. Байткод и виртуальная машина дают переносимость и динамику ценой того, что типы и выбор нужной операции разрешаются во время работы. Промежуточный вариант это JIT, который компилирует горячие участки прямо в рантайме, как делает PyPy.
Где спотыкаются
Повторяют школьную формулу про выполнение построчно. Синтаксическая ошибка в конце модуля не даст выполниться ни одной строке в его начале, потому что компиляция в байткод идёт до запуска, и интервьюер показывает это одним примером.
Второе: говорят, что интерпретируемый язык не порождает файлов. Файлы байткода создаются и переиспользуются, поэтому повторный импорт того же модуля стартует быстрее, а сам байткод привязан к версии интерпретатора и между ними не переносится.
Третье: делят языки на два списка. Для Python есть и реализация с JIT, и компиляция в расширение через Cython, а для C существуют интерпретаторы, так что корректная формулировка всегда про конкретную реализацию, а не про язык вообще.