CPython Çalışma Zamanında Python Kodunun AST Bytecode PVM Yolculuğu

python dev.to

CPython Çalışma Zamanında Python Kodunun AST → Bytecode → PVM Yolculuğu

Bir Python geliştiricisi için aşağıdaki soru oldukça önemlidir:

CPython çalışma zamanı ortamında bir .py dosyası çalıştırıldığında, kaynak kodun AST seviyesinden Bytecode seviyesine dönüştürülmesi ve Python Virtual Machine (PVM) üzerinde yürütülmesi sürecinde ilk gerçekleşen aşama nedir?

Doğru cevap:

Kaynak kodun tokenize edilerek Parse Tree'ye dönüştürülmesi ve ardından AST'nin oluşturulmasıdır.

Bu cevabı gerçekten anlayabilmek için CPython'un bir Python dosyasını nasıl çalıştırdığına derinlemesine bakalım.


Genel Mimari

Bir Python dosyası çalıştırıldığında CPython aşağıdaki adımları izler:

Python Kaynak Kodu (.py)
          │
          ▼
      Tokenizer
          │
          ▼
       Parser
          │
          ▼
      Parse Tree
          │
          ▼
         AST
          │
          ▼
 Bytecode Compiler
          │
          ▼
       Bytecode
          │
          ▼
      PVM (Python Virtual Machine)
          │
          ▼
       Sonuç
Enter fullscreen mode Exit fullscreen mode

1. Kaynak Kodun Okunması

Örnek Python kodumuz:

x = 10
y = 20
print(x + y)
Enter fullscreen mode Exit fullscreen mode

CPython ilk olarak dosyayı diskten okur.

Bu aşamada elimizde sadece metin vardır.

"x = 10\ny = 20\nprint(x+y)"
Enter fullscreen mode Exit fullscreen mode

Henüz Python neyin değişken, neyin sayı olduğunu bilmez.


2. Tokenization (Lexical Analysis)

İlk gerçek derleme adımı budur.

Tokenizer kaynak kodu küçük anlamlı parçalara ayırır.

Örneğimiz:

x = 10
Enter fullscreen mode Exit fullscreen mode

şuna dönüşür:

NAME     x
OP       =
NUMBER   10
NEWLINE
Enter fullscreen mode Exit fullscreen mode

Tüm program için:

NAME(x)
=
NUMBER(10)

NAME(y)
=
NUMBER(20)

NAME(print)
(
NAME(x)
+
NAME(y)
)
Enter fullscreen mode Exit fullscreen mode

Bu parçalara Token denir.


Token Nedir?

Token programlama dilinin en küçük anlamlı birimidir.

Örneğin:

if x > 5:
Enter fullscreen mode Exit fullscreen mode

tokenlere ayrılır:

IF
NAME(x)
GREATER_THAN
NUMBER(5)
COLON
Enter fullscreen mode Exit fullscreen mode

3. Parsing

Tokenlar tek başlarına yeterli değildir.

Parser bunların gramer kurallarına uygun olup olmadığını kontrol eder.

Örneğin:

x = 10
Enter fullscreen mode Exit fullscreen mode

geçerli bir ifadedir.

Ama:

= x 10
Enter fullscreen mode Exit fullscreen mode

gramere uymaz.

Parser hata verir:

SyntaxError
Enter fullscreen mode Exit fullscreen mode

Parse Tree Oluşturulması

Parser başarılı olursa bir Parse Tree üretir.

Örneğin:

x = 10
Enter fullscreen mode Exit fullscreen mode

için:

Assignment
├── Variable(x)
└── Number(10)
Enter fullscreen mode Exit fullscreen mode

Bu yapı Python dilinin dilbilgisine bağlıdır.

Çok detaylıdır.

Bu nedenle bir sonraki aşamada sadeleştirilir.


4. AST (Abstract Syntax Tree)

AST = Soyut Sözdizimi Ağacı

Parse Tree'deki gereksiz gramer detayları kaldırılır.

Örnek:

x = 10
Enter fullscreen mode Exit fullscreen mode

AST:

Assign
├── Name(x)
└── Constant(10)
Enter fullscreen mode Exit fullscreen mode

Daha karmaşık örnek:

result = x + y * 2
Enter fullscreen mode Exit fullscreen mode

AST:

Assign
├── Name(result)
└── BinOp(+)
     ├── Name(x)
     └── BinOp(*)
          ├── Name(y)
          └── Constant(2)
Enter fullscreen mode Exit fullscreen mode

AST artık programın mantıksal yapısını temsil eder.


AST'yi Python İçinden Görmek

import ast

code = """
x = 10
y = 20
print(x+y)
"""

tree = ast.parse(code)

print(ast.dump(tree, indent=4))
Enter fullscreen mode Exit fullscreen mode

Çıktı:

Module(
    body=[
        Assign(...),
        Assign(...),
        Expr(...)
    ]
)
Enter fullscreen mode Exit fullscreen mode

CPython'un derleyicisi de tam olarak bu AST üzerinden çalışır.


5. Bytecode Üretimi

AST daha sonra Bytecode Compiler'a gönderilir.

Burada Python'a özgü sanal makine komutları üretilir.

Örnek:

x = 10
print(x)
Enter fullscreen mode Exit fullscreen mode

Bytecode'u Görüntüleme

import dis

def demo():
    x = 10
    print(x)

dis.dis(demo)
Enter fullscreen mode Exit fullscreen mode

Çıktı benzeri:

LOAD_CONST 10
STORE_FAST x

LOAD_GLOBAL print
LOAD_FAST x

CALL
POP_TOP

RETURN_VALUE
Enter fullscreen mode Exit fullscreen mode

Artık Python kodu yoktur.

Artık Bytecode vardır.


Bytecode Nedir?

Bytecode:

  • Makine kodu değildir
  • CPU tarafından çalıştırılamaz
  • Platform bağımsızdır
  • PVM tarafından çalıştırılır

Bir anlamda:

Python Kaynak Kodu
       ↓
Bytecode
       ↓
Makine Kodu
Enter fullscreen mode Exit fullscreen mode

şeklinde düşünebiliriz.


6. .pyc Dosyası Oluşturulması

CPython bytecode'u cacheleyebilir.

__pycache__/
Enter fullscreen mode Exit fullscreen mode

altında:

main.cpython-313.pyc
Enter fullscreen mode Exit fullscreen mode

gibi dosyalar oluşur.

Bunlar doğrudan Bytecode içerir.

Ama dikkat:

.pyc = Bytecode
Enter fullscreen mode Exit fullscreen mode

değildir tamamen.

İçinde ayrıca:

  • sürüm bilgisi
  • timestamp
  • metadata

bulunur.


7. Python Virtual Machine (PVM)

Bytecode artık çalıştırılmaya hazırdır.

Devreye PVM girer.

PVM:

LOAD_CONST
STORE_FAST
LOAD_FAST
CALL
RETURN_VALUE
Enter fullscreen mode Exit fullscreen mode

gibi komutları tek tek işler.


PVM Döngüsü

Basitleştirilmiş hali:

while True:
    instruction = next_instruction()

    execute(instruction)
Enter fullscreen mode Exit fullscreen mode

Gerçekte CPython'un kalbi olan:

ceval.c
Enter fullscreen mode Exit fullscreen mode

dosyasında çalışır.

Temel yapı:

for (;;) {
    opcode = NEXTOP();
    switch(opcode) {
        ...
    }
}
Enter fullscreen mode Exit fullscreen mode

şeklindedir.

Buna:

Interpreter Loop

veya

Evaluation Loop

denir.


Stack-Based Mimari

PVM bir stack kullanır.

Örnek:

print(2 + 3)
Enter fullscreen mode Exit fullscreen mode

Bytecode:

LOAD_CONST 2
LOAD_CONST 3
BINARY_ADD
PRINT
Enter fullscreen mode Exit fullscreen mode

Stack hareketi:

[]
Enter fullscreen mode Exit fullscreen mode
[2]
Enter fullscreen mode Exit fullscreen mode
[2,3]
Enter fullscreen mode Exit fullscreen mode
[5]
Enter fullscreen mode Exit fullscreen mode
[]
Enter fullscreen mode Exit fullscreen mode

Bu yüzden Python VM'e:

Stack Based Virtual Machine

denir.


Gerçek Süreç Adım Adım

Kod:

x = 10
y = 20
print(x+y)
Enter fullscreen mode Exit fullscreen mode

CPython içinde:

Adım 1

Kaynak kod okunur.

Source Code
Enter fullscreen mode Exit fullscreen mode

Adım 2

Tokenization

NAME
NUMBER
OPERATOR
Enter fullscreen mode Exit fullscreen mode

Adım 3

Parsing

Parse Tree
Enter fullscreen mode Exit fullscreen mode

Adım 4

AST oluşturulur.

Abstract Syntax Tree
Enter fullscreen mode Exit fullscreen mode

Adım 5

Compiler çalışır.

Bytecode
Enter fullscreen mode Exit fullscreen mode

Adım 6

Bytecode oluşturulur.

.pyc
Enter fullscreen mode Exit fullscreen mode

Adım 7

PVM bytecode'u yürütür.

Execution
Enter fullscreen mode Exit fullscreen mode

Adım 8

Program sonucu üretilir.


Mülakat ve Sertifikasyon İçin Kritik Bilgi

Sorudaki ifade:

"AST seviyesinden Bytecode seviyesine dönüştürülmesi ve PVM üzerinde çalıştırılması sürecinde ilk gerçekleşen aşama hangisidir?"

cevaplanırken birçok kişi doğrudan:

AST → Bytecode
Enter fullscreen mode Exit fullscreen mode

dönüşümünü düşünür.

Fakat AST'nin oluşabilmesi için önce:

  1. Source Code okunur
  2. Tokenization yapılır
  3. Parse Tree oluşturulur
  4. AST oluşturulur

Bu nedenle süreçte ilk gerçekleşen kritik derleme aşaması:

Kaynak kodun tokenize edilmesi, Parse Tree'nin oluşturulması ve ardından AST'nin inşa edilmesidir.

Bu aşama tamamlanmadan Bytecode üretimine geçilemez ve PVM'in çalıştıracağı hiçbir komut oluşamaz.


Özet

CPython'un yürütme zinciri:

.py Source Code
        │
        ▼
Tokenization
        │
        ▼
Parsing
        │
        ▼
Parse Tree
        │
        ▼
AST
        │
        ▼
Bytecode Compiler
        │
        ▼
Bytecode (.pyc)
        │
        ▼
Python Virtual Machine (PVM)
        │
        ▼
Program Execution
Enter fullscreen mode Exit fullscreen mode

Dolayısıyla sorudaki doğru yaklaşım:

İlk olarak kaynak kod tokenize edilir, Parse Tree oluşturulur ve bu yapıdan AST üretilir. Bytecode üretimi ve PVM yürütmesi daha sonraki aşamalardır.

Source: dev.to

arrow_back Back to Tutorials