Czy Python jest interpretowany, kompilowany, czy jedno i drugie?

190

Z mojego zrozumienia:

Interpretowany język jest prowadzony język wysokiego poziomu i wykonywane przez tłumacza (program, który konwertuje język wysokiego poziomu do kodu maszynowego, a następnie wykonanie) w podróży; przetwarza program po trochu.

Zestawiane język jest w języku wysokiego poziomu, w której kod jest przekształcany do maszynowego kodu przez kompilator (programu, który przekształca języka wysokiego poziomu na kod maszynowy), a następnie wykonywane przez wykonawcy (inny program do uruchamiania kodu).

Popraw mnie, jeśli moje definicje są błędne.

Teraz wracając do Pythona, jestem trochę zdezorientowany. Wszędzie, gdzie dowiadujesz się, że Python jest językiem interpretowanym, ale jest interpretowany do jakiegoś kodu pośredniego (jak bajt-code lub IL), a nie do kodu maszynowego. Który program wykonuje kod IM? Pomóż mi zrozumieć, w jaki sposób skrypt Python jest obsługiwany i uruchamiany.

Pankaj Upadhyay
źródło
2
Python tworzy pliki .pyc (tzw. Byecode) za każdym razem, gdy biblioteka jest importowana. AFAIK kod bajtowy może tylko przyspieszyć czasy ładowania, a nie czasy wykonania.
Jesvin Jose
2
@ aitchnyu: Buforowanie kodu bajtowego w plikach .pyc rzeczywiście tylko przyspiesza ładowanie, ale tylko dlatego, że kod Pythona jest kompilowany do kodu bajtowego przed wykonaniem. Chociaż nie sądzę, że zostało to wypróbowane specjalnie dla Pythona, inne implementacje językowe pokazują, że kod bajtowy jest rzeczywiście łatwiejszy do interpretacji wydajniej niż zwykły AST lub, co gorsza, nie analizowany kod źródłowy. Na przykład starsze wersje Rubiego interpretowane przez AST i były znacznie lepsze niż AFAIK dzięki nowszym wersjom kompilowanym do kodu bajtowego.
Nie chcesz brzmieć niegrzecznie, ale czy nie to miałem na myśli (ale nie tak poinformowany jak ty)?
Jesvin Jose
1
@aitchnyu: Nie wiem o co ci chodziło. Wiem tylko, że twój komentarz nie był niepoprawny, ale zapewnił dobrą przeciwność dla niektórych podstawowych informacji, dlaczego to tylko przyspiesza czas ładowania, więc postanowiłem dodać tę informację. Żadne przestępstwo nie miało znaczenia ani nie zostało odebrane :)

Odpowiedzi:

232

Po pierwsze, interpretacja / kompilacja nie jest własnością języka, ale właściwością implementacji. W przypadku większości języków większość, jeśli nie wszystkie implementacje, należą do jednej kategorii, więc można zapisać kilka słów, mówiąc, że język jest również interpretowany / kompilowany, ale nadal jest to ważne rozróżnienie, zarówno dlatego, że pomaga w zrozumieniu, jak i dlatego, że istnieje wiele języków z użytecznymi implementacjami obu rodzajów (głównie w dziedzinie języków funkcjonalnych, patrz Haskell i ML). Ponadto istnieją interpretery C i projekty, które próbują skompilować podzbiór języka Python do kodu C lub C ++ (a następnie do kodu maszynowego).

Po drugie, kompilacja nie ogranicza się do kompilacji z wyprzedzeniem do natywnego kodu maszynowego. Kompilator to, bardziej ogólnie, program, który konwertuje program z jednego języka programowania na program w innym języku programowania (prawdopodobnie można nawet mieć kompilator z tym samym językiem wejściowym i wyjściowym, jeśli zastosowane zostaną znaczące transformacje). Kompilatory JIT kompilują się w natywnym kodzie maszynowym w czasie wykonywania , co może zapewnić szybkość bardzo zbliżoną lub nawet lepszą niż kompilacja z wyprzedzeniem (w zależności od testu porównawczego i jakości porównywanych implementacji).

Ale żeby przestać nitpicking i odpowiedzieć na pytanie, które chciałeś zadać: Praktycznie (czytaj: używając nieco popularnej i dojrzałej implementacji), Python jest kompilowany . Nieskompilowany z wyprzedzeniem do kodu maszynowego (tj. „Skompilowany” przez ograniczoną i niepoprawną, ale niestety wspólną definicję), „tylko” skompilowany do kodu bajtowego , ale nadal jest kompilacją z przynajmniej niektórymi zaletami. Na przykład instrukcja a = b.c()jest kompilowana do strumienia bajtów, który po zdemontowaniu wygląda trochę jak load 0 (b); load_str 'c'; get_attr; call_function 0; store 1 (a). Jest to uproszczenie, w rzeczywistości jest mniej czytelne i nieco bardziej niskiego poziomu - możesz eksperymentować ze standardowym dismodułem bibliotecznym i zobaczyć, jak wygląda prawdziwa okazja.

Ten kod bajtowy jest albo interpretowany (zauważ, że istnieje różnica, zarówno w teorii, jak i w praktyce, między bezpośrednią interpretacją a pierwszą kompilacją do jakiejś pośredniej reprezentacji i interpretacji tego), jak w przypadku implementacji referencyjnej (CPython), lub obie interpretowane i kompilowane do zoptymalizowany kod maszynowy w czasie wykonywania, tak jak w przypadku PyPy .

jsmedmar
źródło
2
W porządku, oznacza to, że skrypt Pythona jest najpierw kompilowany do kodu bajtowego, a następnie implementowany przez interpretera takiego jak CPython, Jython lub IronPython itp.
Pankaj Upadhyay 31'11
19
Nie, jest kompilowany do kodu bajtowego, a następnie kod bajtowy jest wykonywany przez odpowiednią maszynę wirtualną. CPython jest zarówno kompilatorem, jak i maszyną wirtualną, ale Jython i IronPython to tylko kompilator.
Ignacio Vazquez-Abrams
1
@Igacio: Nie mam dużego doświadczenia z IronPython / Jython, ale czy przynajmniej Jython nie zapewnia warstwy podobnej do interpretera? Nie sądzę, aby można było zmienić Python w statyczny kod bajtowy JVM. Nadal jednak należy pamiętać, że kompilator i interpreter są częścią tego samego pakietu.
2
+1 „... właściwość implementacji”. Ja sam powiedziałbym „pozwala na interaktywną powłokę”
Jesvin Jose
2
@delnan: Cóż, Jython działa jako rodzaj pośrednika między językiem Python a wirtualną maszyną Java, ale kompiluje się do kodu bajtowego Java.
Ignacio Vazquez-Abrams
34

Procesor rzeczywiście może zrozumieć tylko kod maszynowy. W przypadku interpretowanych programów ostatecznym celem interpretera jest „interpretacja” kodu programu na kod maszynowy. Jednak zwykle nowoczesny język interpretowany nie interpretuje kodu ludzkiego bezpośrednio, ponieważ jest zbyt mało wydajny.

Interpreter języka Python najpierw odczytuje kod ludzki i optymalizuje go do jakiegoś kodu pośredniego przed interpretacją go na kod maszynowy. Dlatego zawsze potrzebujesz innego programu do uruchomienia skryptu Python, w przeciwieństwie do C ++, w którym możesz bezpośrednio uruchomić skompilowany plik wykonywalny swojego kodu. Na przykład c:\Python27\python.exelub /usr/bin/python.

Jeremy
źródło
11
Podoba mi się to, że „potrzebuję innego programu do uruchomienia [it]”. To pomogło wyjaśnić niektóre moje myśli.
Matt
więc python.exe najpierw optymalizuje kod, a następnie interpretuje go?
Koray Tugay,
@KorayTugay, gdy python.exe otrzymuje kod źródłowy czytelny dla człowieka, najpierw tworzy zoptymalizowany kod bajtowy, a następnie interpretuje to (jak mówisz); jednak gdy już istnieje bajtowy plik kodu (wstępnie skompilowany), nie musi on wykonywać pierwszego kroku, co oszczędza trochę czasu.
GordonBGood
31

Odpowiedź zależy od zastosowanej implementacji Pythona. Jeśli używasz powiedzmy CPython (Standardowa implementacja Pythona) lub Jython (Przeznaczony do integracji z językiem programowania Java), najpierw jest tłumaczony na kod bajtowy , aw zależności od implementacji używanego Pythona, ten kod jest kierowany do odpowiedniego maszyna wirtualna do interpretacji . PVM (Python Virtual Machine) dla CPython i JVM (Java Virtual Machine) dla Jython.

Ale powiedzmy, że używasz PyPy, który jest kolejną standardową implementacją CPython. Byłoby użyć Just-In-Time Compiler .

test jakości
źródło
Podczas tłumaczenia kodu bajtowego potrzebny jest kompilator, który to jest?
RICKY
Pypy to implementacja w języku Python , a nie implementacja „CPython”. W rzeczywistości Pypy jest alternatywą dla CPython ( pypy.org/features.html ).
Giorgio
13

Według oficjalnej strony Python jest to język interpretowany.

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

Python jest interpretowanym, obiektowym językiem programowania wysokiego poziomu ...

...

Ponieważ nie ma kroku kompilacji ...

...

Interpreter języka Python i obszerna biblioteka standardowa są dostępne ...

...

Zamiast tego, gdy interpreter wykryje błąd, zgłasza wyjątek. Gdy program nie wychwytuje wyjątku, interpreter drukuje ślad stosu.

John S.
źródło
7

Tak, jest to zarówno język skompilowany, jak i interpretowany. Dlaczego na ogół nazywamy to tłumaczonym językiem?

zobaczyć, jak jest zarówno kompilowana, jak i interpretowana?

Przede wszystkim chcę powiedzieć, że bardziej spodoba ci się moja odpowiedź, jeśli pochodzisz ze świata Java.

W Javie kod źródłowy jest najpierw konwertowany na kod bajtowy za pomocą kompilatora javac, a następnie kierowany do JVM (odpowiedzialnego za generowanie kodu natywnego w celu wykonania). Teraz chcę pokazać, że nazywamy Javę językiem kompilowanym, ponieważ widzimy, że naprawdę kompiluje kod źródłowy i przekazuje plik .class (tylko kod bajtowy) poprzez:

javac Hello.java -------> tworzy plik Hello.class

java Witaj --------> Przekierowanie kodu bajtowego do JVM w celu wykonania

To samo dzieje się z Pythonem, tzn. Najpierw kod źródłowy jest konwertowany na kod bajtowy przez kompilator, a następnie kierowany do PVM (odpowiedzialnego za generowanie kodu natywnego w celu wykonania). Teraz chcę pokazać, że zwykle wywołujemy Python jako język interpretowany, ponieważ kompilacja odbywa się za sceną i kiedy uruchamiamy kod Pythona poprzez:

python Hello.py -------> bezpośrednio wycina kod i widzimy, że dane wyjściowe dowodzą, że kod jest poprawny pod względem składniowym

@ python Hello.py wygląda na to, że wykonuje bezpośrednio, ale tak naprawdę najpierw generuje kod bajtowy, który jest interpretowany przez interpretera w celu wygenerowania kodu natywnego na potrzeby wykonania.

CPython - bierze odpowiedzialność zarówno za kompilację, jak i interpretację.

Spójrz na poniższe linie, jeśli potrzebujesz więcej szczegółów :

Jak już wspomniałem, CPython kompiluje kod źródłowy, ale faktyczna kompilacja odbywa się za pomocą cytonu, następnie interpretacja odbywa się za pomocą CPython

Porozmawiajmy teraz trochę o roli kompilatora Just-In-Time w Javie i Pythonie

W JVM istnieje interpreter Java, który interpretuje kod bajt linia po linii, aby uzyskać natywny kod maszynowy do wykonania, ale gdy kod bajtowy Java jest wykonywany przez interpretera, wykonanie zawsze będzie wolniejsze. Więc jakie jest rozwiązanie? rozwiązaniem jest kompilator Just-In-Time, który wytwarza natywny kod, który można wykonać znacznie szybciej niż można to zinterpretować. Niektórzy dostawcy JVM używają interpretera Java, a niektórzy kompilatora Just-In-Time . Odniesienie: kliknij tutaj

W Pythonie, aby obejść interpreter w celu szybkiego wykonania, użyj innej implementacji Pythona ( PyPy ) zamiast CPython . kliknij tutaj, aby zobaczyć inne implementacje Pythona, w tym PyPy .

Chirag Soni
źródło
6

Jeśli (znasz Javę) {

kod Pythona jest konwertowany na kod bajtowy, tak jak robi to Java.
Ten kod bajtowy jest wykonywany ponownie za każdym razem, gdy próbujesz uzyskać do niego dostęp.

} else {

Kod Pythona jest początkowo tłumaczony na coś, co nazywa się bytecode,
który jest dość zbliżony do języka maszynowego, ale nie rzeczywistego kodu maszynowego,
więc za każdym razem, gdy uzyskujemy do niego dostęp lub uruchamiamy, kod bajtowy jest wykonywany ponownie

}

Nabil Qadir
źródło
2

Prawie możemy powiedzieć, że Python jest językiem interpretowanym. Ale używamy pewnej części jednorazowego procesu kompilacji w Pythonie do konwersji pełnego kodu źródłowego na kod bajtowy, taki jak język Java.

Hemant
źródło
1

Dla początkujących

Python automatycznie kompiluje skrypt do skompilowanego kodu, tzw. Kodu bajtowego, przed jego uruchomieniem.

Uruchomienie skryptu nie jest uważane za import i nie zostanie utworzony plik .pyc.

Na przykład, jeśli masz plik skryptu abc.py, który importuje inny moduł xyz.py, po uruchomieniu abc.py, xyz.pyc zostanie utworzony od czasu importu xyz, ale od abc nie zostanie utworzony plik abc.pyc. py nie jest importowane.

navaneeth kt
źródło
1

Jest to duże zamieszanie dla osób, które rozpoczęły pracę nad pytonem, a odpowiedzi tutaj są trochę trudne do zrozumienia, więc ułatwię to.

Kiedy instruujemy Python, aby uruchomił nasz skrypt, jest kilka kroków, które wykonuje Python, zanim nasz kod zacznie się rozpadać:

  • Jest kompilowany do kodu bajtowego.
  • Następnie jest kierowany do maszyny wirtualnej.

Kiedy wykonujemy kod źródłowy, Python kompiluje go w kod bajtowy. Kompilacja jest krokiem tłumaczenia, a kod bajtowy jest reprezentacją kodu źródłowego niezależną od platformy reprezentacją niskiego poziomu. Zauważ, że bajtowy kod Pythona nie jest binarnym kodem maszynowym (np. Instrukcje dla układu Intel).

W rzeczywistości Python tłumaczy każdą instrukcję kodu źródłowego na instrukcje kodu bajtowego, rozkładając je na poszczególne kroki. Tłumaczenie kodu bajtowego jest wykonywane w celu przyspieszenia wykonania. Kod bajtowy można uruchomić znacznie szybciej niż oryginalne instrukcje kodu źródłowego. Ma rozszerzenie.pyc i zostanie zapisane, jeśli będzie mogło pisać na naszym komputerze.

Zatem następnym razem, gdy uruchomimy ten sam program, Python załaduje plik .pyc i pominie krok kompilacji, chyba że został zmieniony. Python automatycznie sprawdza znaczniki czasowe plików kodu źródłowego i bajtowego, aby wiedzieć, kiedy należy go ponownie skompilować. Jeśli ponownie zapisamy kod źródłowy, kod bajtu jest automatycznie tworzony ponownie przy następnym uruchomieniu programu.

Jeśli Python nie może zapisać plików kodu bajtów na naszym komputerze, nasz program nadal działa. Kod bajtu jest generowany w pamięci i po prostu odrzucany przy wyjściu z programu. Ale ponieważ pliki .pyc skracają czas uruchamiania, możemy chcieć się upewnić, że został napisany dla większych programów.

Podsumujmy, co dzieje się za kulisami. Kiedy Python wykonuje program, Python wczytuje plik .py do pamięci i analizuje go w celu uzyskania kodu bajtowego, a następnie uruchamia się. Dla każdego modułu importowanego przez program Python najpierw sprawdza, czy istnieje wstępnie skompilowana wersja kodu bajtowego w .pyo lub .pyc, która ma znacznik czasu odpowiadający jego plikowi .py. Python używa wersji kodu bajtowego, jeśli istnieje. W przeciwnym razie analizuje plik .py modułu, zapisuje go w pliku .pyc i używa właśnie utworzonego kodu bajtowego.

Pliki z kodami bajtów są również jednym ze sposobów przesyłania kodów w języku Python. Python nadal uruchomi program, jeśli wszystko, co może znaleźć, to pliki.p.p, nawet jeśli nie ma tam oryginalnych plików źródłowych .py.

Python Virtual Machine (PVM)

Gdy nasz program zostanie skompilowany do kodu bajtowego, jest wysyłany do wykonania w Python Virtual Machine (PVM). PVM nie jest osobnym programem. Nie musi być instalowany sam. W rzeczywistości PVM to po prostu duża pętla, która iteruje kolejno nasze instrukcje bajtów, aby wykonywać swoje operacje. PVM to silnik wykonawczy Pythona. Jest zawsze obecny jako część systemu Python. To składnik, który naprawdę uruchamia nasze skrypty. Technicznie jest to tylko ostatni krok tak zwanego interpretera języka Python.

erastone
źródło
0

Kod Pythona, który piszesz, jest kompilowany do kodu bajtowego Pythona, który tworzy plik z rozszerzeniem .pyc. Jeśli się kompiluje, znowu pytanie brzmi: dlaczego nie skompilować języka.

Zauważ, że nie jest to kompilacja w tradycyjnym tego słowa znaczeniu. Zazwyczaj mówimy, że kompilacja przyjmuje język wysokiego poziomu i konwertuje go na kod maszynowy. Ale jest to swego rodzaju kompilacja. Skompilowany do kodu pośredniego, a nie do kodu maszynowego (mam nadzieję, że teraz go masz).

Wracając do procesu wykonywania, twój kod bajtowy, obecny w pliku pyc, utworzony w kroku kompilacji, jest następnie wykonywany przez odpowiednie maszyny wirtualne, w naszym przypadku CPython VM. Znacznik czasu (nazywany magiczną liczbą) służy do sprawdzenia, czy. plik py jest zmieniany lub nie, w zależności od tego, jaki nowy plik pyc jest tworzony. Jeśli pyc ma bieżący kod, po prostu pomija krok kompilacji.

y durga prasad
źródło
0

Python (interpreter) jest kompilowany .

Dowód: nawet nie skompiluje kodu, jeśli zawiera błąd składniowy .

Przykład 1:

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

Wynik:

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

Kod został pomyślnie skompilowany. Pierwsza linia zostanie wykonana ( print) druga linia wyrzuci ZeroDivisionError(błąd czasu wykonywania).

Przykład 2:

print("This should not print")
/0         

Wynik:

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

Wniosek : jeśli plik kodu SyntaxErrornie zawiera niczego, nie zostanie wykonany, ponieważ kompilacja się nie powiedzie.

Czarnobrody
źródło