Python interpretasiya, yoxsa kompilyasiya olunur ? — 2-ci hissə

Kamran Mammadov
Pragmatech
Published in
3 min readMar 28, 2020

Məqalənin birinci hissəsində (buradan oxuya bilərsiniz) pythonun interpretator, yoxsa kompilyator dil olduğunu, mənbə kodların kompyuter tərəfindən anlaşılana və nəticə qaytaranadək keçdiyi mərhələləri müəyyənləşdirdik. Mərhələləri analiz edərkən .pyc faylından, baytkodlardan (anlayış olaraq) və onların Python Virtual Maşınında (PVM) icra olunduğundan da bəhs etdik. Bu dəfə, məhz bu icra prosesinin necə baş verdiyindən yazacam.

Bir daha qeyd edək ki, Python mənbə kodlarını virtual maşının başa düşəcəyi dilə — baytkodlara çevirir və həmin virtual maşın interpretator rolunu oynayır. Deməli, yazılan kodların müəyyən bir nəticə qaytarmasında rol oynayan 3 əsas iştirakçımız .pyc, baytkod və adını yeni eşidəcəyimiz CPythondur.

CPython

Cpython standart Python interpretatorudur. Yəni, əslində iki məqalədir dilimizdən düşməyən və virtual maşında icra olunan baytkodları yaradan(!) alətdir. CPython adını C və Pythonda yazıldığı üçün bu dillərdən almışdır, lakin bununla yanaşı fərqli dillərdə yazılan bir neçə Python interpretatoru da mövcuddur. Onlardan bəziləri aşağıdakılardır:

  1. IronPython
  2. Jython
  3. PyPy
  4. Stackless Python
  5. PythonNet və s.

Qeyd: Məqalənin kontentində dəfələrlə push və pop terminlərindən istifadə olunacaq. Öncə aşağıdakı abzasda əlavə olunan linkdən bu terminlərlə tanış olmaq məsləhət görülür.

Python Virtual Maşını (PVM)

CPython-ın istifadə etdiyi virtual maşın stack-based-dir (bax: Stacks and Queues in Python). Stack-based tamamilə stack data tiplərinə yönəlmiş yanaşma anlamına gəlir (yeni məlumatın siyahının əvvəlinə push olunması və ya əvvəlindən pop olunması). CPython üç növ stack-dən istifadə edir:

  1. The call stack Python proqramının icra olunma konsepsiyasının əsas strukdurudur. İşləmə prinsipinin kökündə “frame” adlanan funksiya “çağırıcılar”ı dayanır. Niyə funksiya çağırıcıları kimi adlandırma edirəm, çünki proqrama giriş aktiv bir funksiyanın çağırılması ilə başlayır. Bu “frame”lər stack şəklində düzülürlər. Hər bir funksiyanın çağırılması ilə stack-ə yeni frame push olunur, hər bir funksiya bir dəyər qaytardıqda isə frame-lər bir-bir pop olunur.
  2. The evaluation stack (və ya data stack) — Hər bir frame-in daxilində(!) yer alır. Bu, funksiyanın icrasının yarandığı stack-dir və əslində Python kodunun icra olunması prosesi bu stack-ə data push etmək və ya pop etməkdən ibarətdir.
  3. The block stack — Hər bir frame daxilində data stack-lə bərabər yer alır. Bu stack Python tərəfindən dövr, try/except with blokları kimi kontrol strukturlarının izlənməsi üçün istifadə olunur. Bu kontrol strukturları tanındıqca 2-ci punktda bəhs edilən icra prosesi kimi sözügedən stack-ə data push və ya pop edir, yəni bloka daxil olanda məlumat block stack-ə push olunur, blokdan çıxdıqda əlavə olunan məlumat bu stack-dən pop olunur. Bu proses Python-a hazırda hansı blokun aktiv olduğunu “anlamağa” yardımçı olur.

Generasiya olunan baytkodların böyük əksəriyyəti call-stack(1) frame-nin evalution stack-ni(2) manipulyasiya etmək işini görür (təbii ki, qalan hissəsi block stack-ə müdaxilə edir).

Fərz edək ki, aşağıdakı kimi iki parametrə malik, ötürülən arqumentlə 10 ədədini toplayan bəsit bir funksiyanı çağıran kiçik bir kod blokumuz var:

kamrans_function(kamrans_argument, 10)

Python bu kod blokunu başa düşmək üçün onu 4 mərhələdə baytkodlara ayıracaq:

  1. LOAD_NAME — mənbə kodunun içərisində funksiya axtarır və tapdığı halda evaluation stack-ə push edir.
  2. Daha bir LOAD_NAME — funksiyanın içərisinə ötürülmüş kamrans_argument arqumentini axtarır və evaluation stack-ə push edir.
  3. LOAD_CONST — funksiyanın sabit dəyərə malik 10 parametrini evaluation stack-ə push edir.
  4. CALL_FUNCTION — iki arqument alacaq. Bu da o deməkdir ki, Python stack-dən iki arqument pop etməlidir; sonra çağırılacaq funksiya stack-in üst səviyyəsində yer alacaq, çağırıldıqdan sonra isə pop olunacaq (keyword argumentli olan funksiyalar üçün CALL_FUNCTION_KW işə salınır). Bütün bu proseslərə “hazır” Python stack-də yeni frame yaradacaq, dəyişənləri çağırılan funksiyaya ötürəcək və bu frame-in içərisində kamrans_function baytkodunu icra edəcək. Bu proseslərdən sonra sözügedən frame stack-dən pop olunacaq və funksiyanın dəyəri evaluation stack-ə push olunacaq.

--

--