Чому Python не потрібен компілятор?


29

Мені просто цікаво (тепер, коли я почав із C ++, який потребує компілятора), чому Python не потрібен компілятор?

Я просто ввожу код, зберігаю його як exec та запускаю його. У мові C ++ я повинен створювати збірки та всі інші цікаві речі.


4
Python - це просто мова з багатьма реалізаціями. Iron Python компілюється так само, як компілюється C # і C ++, і можуть бути й інші його реалізації.
робота

1
C # і C ++ не компілюються однаково - хоча ви можете стверджувати, що вони в кінцевому підсумку закінчуються як машинні інструкції, але якщо ви це зробите, то можна сказати, що BASIC складається також однаково.
gbjbaanb

7
@gbjbaanb, але знову ж таки англійська мова не складається, і семантичний аналіз одного речення може дати два однаково достовірні результати, і вищезгадане можна прочитати як "залізний пітон складається так само, як C # і C ++ складається"
Руна FS

Яку платформу / програмне забезпечення ви використовуєте для написання свого Python-коду? Якщо ви пишете файл .py, він не виконується. Це все ще файл вихідного коду. З командного рядка ви використовуєте pythonкоманду для інтерпретації файлу .py або якщо ви використовуєте IDLE або Eclipse, IDE робить це за вас.
Рік Хендерсон

Відповіді:


68

У Python є компілятор! Ви просто не помічаєте цього, оскільки він працює автоматично. Однак ви можете сказати, що це там: подивіться .pyc(або .pyoякщо у вас оптимізатор увімкнено) файлів, що генеруються для модулів, які ви import.

Крім того, він не компілюється в код рідної машини. Натомість він компілює в байт-код, який використовується віртуальною машиною. Віртуальна машина - сама по собі складена програма. Це дуже схоже на те, як працює Java; насправді настільки схожий, що існує варіант Python ( Jython ), який замість цього компілює байт-код Java Virtual Machine! Є також IronPython , який компілює CLR Microsoft (використовується .NET). (Звичайний компілятор байтового коду Python іноді називається CPython, щоб відключити його від цих альтернатив.)

C ++ потребує викриття процесу компіляції, оскільки сама мова є неповною; він не визначає все, що повинен знати лінкер, щоб створити вашу програму, а також не може вказати варіанти компіляції на портативному рівні (деякі компілятори дозволяють вам використовувати #pragma, але це не стандартно). Тож вам доведеться виконати решту роботи з makefiles та, можливо, авто пекла (autoconf / automake / libtool). Це насправді лише перехід від того, як це робив C. І C зробив це так, оскільки зробив компілятор простим, що є однією з головних причин, якими він користується такою популярністю (хтось міг викрутити простий компілятор C у 80-х).


Деякі речі, які можуть впливати на роботу компілятора чи лінкера, але не вказані в синтаксисі C або C ++:

  • вирішення залежності
  • зовнішні вимоги до бібліотеки (включаючи порядок залежності)
  • рівень оптимізатора
  • налаштування попередження
  • версія специфікації мови
  • відображення лінкерів (який розділ знаходиться в кінцевій програмі)
  • цільова архітектура

Деякі з них можна виявити, але їх неможливо вказати; наприклад, я можу виявити, для чого використовується C ++ __cplusplus, але я не можу вказати, що C ++ 98 є тим, що використовується для мого коду в самому коді; Я повинен передати його як прапор компілятору в Makefile або зробити налаштування в діалоговому вікні.

Хоча ви можете подумати, що в компіляторі існує система "вирішення залежності", яка автоматично генерує записи залежностей, вони записують лише те, які файли заголовків використовує даний вихідний файл. Вони не можуть вказати, які додаткові модулі вихідного коду необхідні для з'єднання у виконувану програму, оскільки в C або C ++ немає стандартного способу вказувати, що даний файл заголовка є визначенням інтерфейсу для іншого модуля вихідного коду на відміну від простої групи рядки, які потрібно показати в декількох місцях, щоб ви не повторювались. Існують традиції у конвенціях про іменування файлів, але вони не відомі і не виконуються компілятором і лінкером.

Деякі з них можна встановити за допомогою #pragma, але це нестандартно, і я говорив про стандарт. Усі ці речі можна було б визначити за допомогою стандарту, але вони не були б зацікавлені у відсталій сумісності. Переважаюча мудрість полягає в тому, що файли та IDE не зламані, тому не виправляйте їх.

Python обробляє все це мовою. Наприклад, importзадає явну залежність модуля, має на увазі дерево залежностей, а модулі не розбиваються на заголовки та вихідні файли (тобто інтерфейс та реалізація).


3
Реалізація Python на C - це CPython , Cython - щось інше.
Грег Х'югілл

4
Інші причини, через які C зібраний до машинного коду, полягав у тому, що він мав бути трохи більше, ніж прославлений асемблер, оскільки інтерпретатори байт-кодів були технічно нездійсненними на апаратному забезпеченні, яке вони мали, і тому що одним із найважливіших завдань було написання ядра ОС.
tdammers

2
@BillyONeal з одним великим винятком, що в c / c ++ ви, як програміст, повинні виконувати речі певним чином (або makefiles, або скидаючи кожну річ у ту саму крапку) у python, ви просто виконуєте свою роботу та компілятор разом з VM піклується про інше
Rune FS

3
"C ++ потрібно розкрити процес компіляції, оскільки сама мова є неповною" Ер, що ??
Гонки легкості з Монікою

3
Ви читаєте частину відразу після цього , правда? "він не визначає все, що повинен знати лінкер для створення вашої програми, а також не може вказати параметри компіляції на портативному рівні." Ви не можете просто створити будь-який файл C ++, подавши його до компілятора; часто вам потрібно надати метадані, такі як прапорці компіляції, включати шляхи тощо. Ці метадані не визначені стандартом і не є портативними, тому нам доводиться перетягувати інші речі, як make, cmake, Visual Studio, або що інше закінчити роботу. Таким чином, стандарт повинен називати деякі речі, як у підрозділі компіляції, а інші - як у програмі.
Майк Десимоне

7

Python - це інтерпретована мова. Це означає, що на вашому комп’ютері є програмне забезпечення, яке зчитує код Python і відправляє "інструкції" на машину. Стаття Вікіпедії про інтерпретовані мови може представляти інтерес.

Коли така мова, як C ++ (мова скомпільована), компілюється, це означає, що вона перетворюється в машинний код, який читається безпосередньо апаратним забезпеченням при виконанні. Стаття у Вікіпедії про складені мови може забезпечити цікавий контраст.


21
Немає такого поняття, як інтерпретована чи складена мова. Мова - це абстрактний набір математичних правил. Мова не компілюється та не інтерпретується. Мова просто є . Компіляція та інтерпретація - це риси укладача чи інтерпретатора (так!), А не мова. Кожна мова може бути реалізована за допомогою компілятора, а кожна мова може бути реалізована за допомогою перекладача. Більшість мов мають компільовані та інтерпретовані реалізації. Є інтерпретатори для C ++ і є компілятори для Python. (Насправді всі існуючі в даний час реалізації Python мають компілятори.)
Jörg W Mittag,

4
Більшість сучасних високопродуктивних мовних реалізацій поєднують як інтерпретатор, так і компілятор (або навіть декілька компіляторів) для досягнення максимальної продуктивності. Насправді запустити будь-яку програму без перекладача неможливо . Зрештою, компілятор - це лише програма, яка переводить програму з однієї мови на іншу. Але в якийсь момент вам доведеться насправді запустити програму, що робиться перекладачем (який може бути, а може і не бути реалізований в кремнії).
Йорг W Міттаг

10
@ JörgWMittag: Ви технічно праві. Однак більшість мов були розроблені для інтерпретованого контексту або для повної компіляції. Написати перекладача для GW BASIC або Common Lisp набагато простіше, ніж написати, наприклад, для C ++ або C #; Python втрачає багато своїх торгових точок без інтерактивного середовища; писати компілятор для PHP досить чортово важко і, ймовірно, жахливо неефективно, оскільки компільований виконуваний файл повинен містити весь інтерпретатор PHP, завдяки eval () та подібним конструкціям - можна стверджувати, що такий компілятор був би обманом.
tdammers

2
@tdammers, так. Ми можемо обгрунтовано використовувати "компільовану мову", щоб означати "мова, яка зазвичай складається". Але це пропускає те, що PHP, Java, Python, Lua і C # всі реалізовані як компілятори для байт-коду. Усі ці мови також мали для них реалізовані JIT. Так що насправді ви не можете назвати деякі з цих мов складеними, а деякі інтерпретовані, оскільки у них однакова стратегія реалізації.
Вінстон Еверт

2
@BillyONeal, не вірно принаймні для python. Ви можете поширити байт-код python і запустити його без джерела. Але це правда, що ви не можете поширити python без компілятора.
Вінстон Еверт

5

Не всі компільовані мови мають цикл редагування-компіляції-запуску посилань.

У що ви стикаєтесь - це функція / обмеження C ++ (або принаймні C ++ реалізацій).

Щоб зробити що-небудь, ви повинні зберегти свій код у файлах та створити монолітне зображення за допомогою процесу, який називається зв'язуванням.

Зокрема, саме цей монолітний процес зв’язування помилково розрізняє складання та інтерпретацію.

Деякі мови роблять все це набагато динамічніше, усуваючи незграбний монолітний крок зв’язку, а не усуваючи компіляцію до машинного коду. Джерело все ще компілюється в об’єктні файли, але вони завантажуються у зображення під час виконання, а не пов'язані в монолітний виконуваний файл.

Ви кажете "перезавантажити цей модуль", і він завантажує джерело та інтерпретує його, або компілює його, залежно від переключення режиму.

Програмування ядра Linux має деякий смак, навіть якщо ви працюєте в C. Ви можете перекомпілювати модуль, завантажити і вивантажити його. Звичайно, ви все ще знаєте, що ви створюєте якусь виконавчу річ, і вона керується складною системою збирання з ще деякими кроками вручну. Але справа в тому, що врешті-решт ви можете вивантажити та перезавантажити саме той невеликий модуль і не доведеться перезавантажувати все ядро.

Деякі мови мають ще більш дрібнозернисту модуляризацію, ніж ця, і збирання та завантаження відбувається в межах їх часу роботи, тому це більш безпроблемно.


2

що відхилення від початкового питання ... Не зазначається, що джерело програми python - це те, що ви використовуєте та розповсюджуєте, з точки зору користувача, це програма. Ми схильні спрощувати речі на категорії, які недостатньо визначені.

Скомпільовані програми зазвичай вважаються окремими файлами машинного коду. (правда, часто містять посилання на бібліотеки динамічних посилань, пов'язані з конкретними операційними системами). Це говорило ... Є більшість мов програмування, які можна описати як складені або інтерпретовані.

Python не потребує компілятора, оскільки він покладається на додаток (званий інтерпретатором), який компілює та запускає код, не зберігаючи створений машинний код у формі, до якої ви можете легко отримати доступ чи поширити.


1

Усі мови програмування потребують перекладу з людських понять у цільовий машинний код. Навіть мова складання повинна бути переведена в машинний код. Цей переклад зазвичай відбувається на наступних етапах:

Фаза 1: Аналіз та переклад (розбір) в проміжний код. Фаза 2: Переклад проміжного коду в цільовий код машини з власниками місць для зовнішніх посилань. Фаза 3: Розв’язання зовнішніх посилань та упаковки у виконану машиною програму.

Цей переклад часто називають попередньою компіляцією та "Тільки вчасно" (JIT) або складанням часу виконання.

Такі мови, як C, C ++, COBOL, Fortran, Pascal (не всі) та Assembly - це попередньо складені мови, які можуть бути виконані безпосередньо системою оперування, не потребуючи перекладача.

Інтерпретуються такі мови, як Java, BASIC, C # та Python. Всі вони використовують проміжний код, створений у Фазі 1, але іноді відрізняються тим, як переводять його в машинний код. Найпростіші форми використовують цей проміжний код для виконання процедур машинного коду, які виконують очікувану роботу. Інші будуть компілювати проміжний код до машинного коду і робити виправлення зовнішньої залежності під час виконання. Після складання його можна негайно виконати. Також машинний код зберігається в кеші попередньо складеного машинного коду для багаторазового використання, який згодом може бути повторно використаний, якщо функція буде потрібна знову. Якщо функція вже кешована, інтерпретатору не потрібно її знову компілювати.

Більшість сучасних мов високого рівня потрапляють до категорії інтерпретованих (з JIT). Здебільшого старі мови, такі як C & C ++, є попередньою компіляцією.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.