Якщо інтерпретується Python, що таке .pyc файли?


1083

Мені дали зрозуміти, що Python - це інтерпретована мова ...
Однак, дивлячись на свій вихідний код Python, я бачу .pycфайли, які Windows ідентифікує як "Компільовані файли Python".

Де вони заходять?


3
Дивіться stackoverflow.com/questions/11433579/… для виправдання. Одним словом: швидкість.
користувач7610



Чи означає це, що навіть у python є те, що "Пишіть один раз, бігайте куди завгодно", як і Java.?
Владар

2
@MrakVladar Навіть Java - "Пишіть один раз, бігайте куди завгодно [що у вас є JVM]". Пітон не відрізняється; це "бігайте туди, де у вас є віртуальна машина Python". Велика різниця полягає в тому, що більшість реалізацій Python поєднують компілятор і інтерпретатор в один виконуваний файл, а не розділяють їх як javaі javac.
чепнер

Відповіді:


660

Вони містять байт-код , до якого інтерпретатор Python компілює джерело. Потім цей код виконується віртуальною машиною Python.

Документація Python пояснює таке визначення:

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


10
Цікаво, дякую. Тож чи вважається Python чисто інтерпретованою мовою?
froadie

194
@froadie: мова не "інтерпретується" або "складена" як така. Конкретна реалізація може бути перекладачем або компілятор (або гібрид або JIT - компілятор).
Йоахім Зауер

30
Один тест "компільований": чи він складений до фактичних інструкцій на машині? Байт-код Python не є машинними вказівками, і жодними не є інструкціями Java 'JVM', тому жодна з цих мов не складається з цього визначення. Але обидва "складені" до проміжного коду "абстрактної машини", і обидва вони набагато швидше, ніж запуск програми, більш-менш безпосередньо інтерпретуючи вихідний код (що і робить стара школа BASIC).
greggo

20
Бути педантичним, "складений" означає "перекладений". Потім Python компілюється в байт-код. AFAIK, насправді інтерпретується лише Bash , всі інші популярні "інтерпретовані" мови всі зібрані в байт-код.
bfontaine

13
Насправді, це інструкції на машині, просто не інструкції з рідної машини для фізичного процесора хоста. Отже, чому ми називаємо це ВМ? Насправді есперанто для асемблерської мови. На сьогоднішній день у нас навіть є власний код для вигаданих (але все ще наслідуваних) процесорів (намагання Mojang зацікавити дітей). Rexx був (або міг бути) по-справжньому інтерпретований, і BAT і CMD (і DCL) інтерпретуються.
mckenzm

994

Мені дали зрозуміти, що Python - це інтерпретована мова ...

Цей популярний мем є неправильним, а точніше, побудованим на нерозумінні (природного) рівня мови: подібна помилка могла б сказати "Біблія - ​​це тверда книга". Дозвольте мені пояснити це зображення ...

"Біблія" - це "книга" в сенсі бути класом (фактичні, фізичні об'єкти, ідентифіковані як) книги; книги, визначені як "копії Біблії", повинні мати щось основне спільне (зміст, хоча навіть вони можуть бути різними мовами, з різними прийнятними перекладами, рівнями виносок та іншими примітками) - однак ці книги є цілком дозволено відрізнятись безліччю аспектів, які не вважаються основоположними - вид палітурки, колір палітурки, шрифт (и), що використовуються для друку, ілюстрації (якщо такі є, широкі поля, що записуються чи ні, числа та види вбудованих закладок) і так далі, і так далі.

Цілком можливо, що типовий друк Біблії дійсно був би в твердій палітурці - зрештою, це книга, яка, як правило, призначена для читання знов і знов, закладена в закладки в декількох місцях, роздумуючи пошук шуканих покажчиків глави та вірша. та ін. Однак, це буденні (практичні) питання, які неможливо використати для визначення того, чи є даний фактичний об'єкт книги копією Біблії чи ні: друковані обкладинки цілком можливі!

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

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

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

Ці форми нижчого рівня потім виконуються відповідними "віртуальними машинами", також відомими як "інтерпретатори" - CPython VM, .Net час виконання, Java VM (відомий також як JVM).

Отже, у цьому сенсі (що роблять типові реалізації) Python - це "інтерпретована мова", якщо і лише тоді, коли є C # і Java: усі вони мають типову стратегію реалізації спочатку створення байтового коду, а потім виконання його через VM / інтерпретатор .

Більш імовірно, що увага зосереджується на тому, наскільки "важкий", повільний і високомобільний процес складання. CPython призначений для компіляції якнайшвидшого, легшого, наскільки це можливо, з якомога меншою церемонією - компілятор робить дуже мало перевірки та оптимізації помилок, тому він може працювати швидко і з невеликою кількістю пам'яті, що в свою чергу дозволяє це запускатись автоматично і прозоро, коли це потрібно, без потреби навіть не знати про те, що компіляція відбувається, більшу частину часу. Java та C # зазвичай приймають більше роботи під час компіляції (і тому не виконують автоматичну компіляцію), щоб більш ретельно перевірити помилки та виконати більше оптимізацій. Це континуум сірих лусочок, а не чорно-біла ситуація,


2
Прекрасна відповідь. Лише невелика поправка до останнього абзацу: Python призначений для компіляції якомога швидше (тощо). Цього разу це справді мова, з відсутністю системи статичного типу та ін. Коли люди говорять про "інтерпретовані" мови, вони зазвичай мають на увазі "динамічні" мови.
Елазар

1
@Elazar, власне, інші реалізації Python, такі як PyPy, які не поспішають компілювати, встигають зробити більш ретельний аналіз, який вимагає відсутність статичного набору тексту, і виробляють своєчасну компіляцію до машинного коду (таким чином, прискорення збільшити багаторічні програми багато разів).
Алекс Мартеллі

Де тут поміщається Cython? Чи вважаєте ви це іншою мовою чи це реалізацією Python? Крім того, чи є цей мем "інтерпретований" проти складеного, можливо, лише термінологічна плутанина, оскільки VM Python часто називають його "інтерпретатором"? Це було б так само справедливо, щоб викликати JVM або .NET інтерпретаторів виконання. Вони в основному інтерпретують байт-код у машинному коді JIT (за винятком деяких винятків оптимізації кешування)
Давос

181

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

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

Мова - це лише набір абстрактних математичних правил. Перекладач - одна з декількох конкретних стратегій реалізації мови. Ці двоє живуть на абсолютно різних рівнях абстракції. Якби англійська мова була набраною мовою, термін "інтерпретована мова" був би помилкою типу. Заява "Python - це інтерпретована мова" не просто хибна (тому що, якщо помилковим буде означати, що твердження навіть має сенс, навіть якщо воно неправильне), воно просто не має сенсу , оскільки мова ніколи не може бути визначена як "інтерпретовано".

Зокрема, якщо ви подивитесь на існуючі в даний час реалізації Python, це стратегії реалізації, які вони використовують:

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

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

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

Зокрема, .pycфайли, які ви бачите, - це кешовані файли байт-кодів, створені CPython, Stackless Python або Unladen Swallow.


5
Основи для старої школи, такі як MSBASIC, не мали проміжної форми. Програма інтерпретувалася безпосередньо з вихідної форми (або поблизу джерела; форма, в якій ключові слова були представлені 1-байтовими маркерами, а рядки # - двобайтовими бінарними вставками, а решта - лише ASCII). Тож насправді «гото» потребуватиме різної кількості часу, залежно від того, скільки джерел рядків довелося шукати, шукаючи відповідне місце призначення. Вирази на зразок * b-2 * cos (x) були ефективно переаналізовані кожного разу, коли вони виконувалися.
greggo

4
@greggo: І якщо ви хочете ще більше старого класу, оригінальна версія BASIC була компілятором нативного коду. Це повинно довести, наскільки смішним є поняття "складеної" чи "інтерпретованої" мови.
Йорг W Міттаг

Дякуємо, що пояснили, як поводяться різні компілятори / інтерпретатори 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.
Йорг W Міттаг

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


38

Це для початківців,

Перед запуском програми Python автоматично компілює ваш сценарій у зібраний код, так званий байт-код.

Запуск сценарію не вважається імпортом, і жоден .pyc не буде створений.

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

Якщо вам потрібно створити .pyc файл для модуля, який не імпортується, ви можете використовувати модулі py_compileта compileall.

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

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

Це дозволить записати .pyc в те саме місце, що і abc.py (ви можете замінити його за допомогою необов'язкового параметра cfile).

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

python -m compileall

Якщо ім'я каталогу (поточний каталог у цьому прикладі) опущено, модуль збирає все, що знаходиться на sys.path


6
і яка користь від компіляції, щоб отримати abc.py?
Сахер Аваль,

@SaherAhwal Однією з переваг, про які я можу придумати, є перевірка синтаксису.
Yi Bao

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. Перейдіть за цим посиланням. Тут процес збирання та виконання коду пояснюється в простому виразі.

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