IlmHamroh
Python kursi/CPython ichki tuzilishi1/8-dars26 daqiqa
Mundarija (21)

12.1-dars: Kod qanday bajariladi: manba → bytecode → VM

12-QISM — CPYTHON ICHKI TUZILISHI · 1-dars


1. Kirish va motivatsiya

11-qismda obyektlar xotirada qanday yashashini ko'rdik. Endi savol: python app.py buyrug'idan keyin kodning o'zi bilan nima sodir bo'ladi?

Real vaziyat. Jamoa FastAPI servisini Kubernetes'ga joylashtirdi. Xavfsizlik talabi bilan konteyner fayl tizimi faqat o'qish rejimida. Har pod ishga tushishi 4 soniyadan 11 soniyaga oshdi, avtomatik masshtablash yuk cho'qqisida ulgurmay qoldi. Sabab: Python har import qilingan modulni qayta kompilyatsiya qilayotgan edi — kompilyatsiya natijasini (__pycache__/*.pyc) diskka yoza olmagani uchun keyingi ishga tushishda ham qayta kompilyatsiya qildi. Yechim — Docker obrazini yig'ish bosqichida python -m compileall bitta qatori. Ishga tushish 3 soniyaga tushdi.

Bu muammoni ko'rish uchun "Python — interpretator, u kodni qatorma-qator o'qiydi" degan tasavvur yetmaydi. Aslida CPython avval butun faylni kompilyator kabi tahlil qiladi va bayt-kodga aylantiradi, keyin bu bayt-kodni o'z virtual mashinasida bajaradi.

Bu darsda:

  • Konveyer: manba → tokenlar → AST → ko'rinish sohalari jadvali → bayt-kod → VM
  • Har bosqichni standart kutubxona bilan ko'rish: tokenize, ast, symtable, compile, dis
  • Kod obyekti (code): nimalardan iborat
  • Kompilyatsiya xatolari va ish vaqti xatolari farqi
  • .pyc fayllar: sarlavha, bekor qilish usullari, compileall
  • Optimallashtirish darajalari: -O, -OO
  • Amaliy: formulalarni bir marta kompilyatsiya qilib, ko'p marta bajarish

2. Nazariya — chuqur tushuntirish

2.1. Konveyer

 app.py (baytlar)
    │  1. Dekodlash       — UTF-8 (yoki # -*- coding -*-)
    ▼
 matn
    │  2. Tokenizator     — NAME, OP, NUMBER, NEWLINE, INDENT ...
    ▼
 tokenlar
    │  3. Parser (PEG)    — grammatika bo'yicha daraxt
    ▼
 AST (abstrakt sintaksis daraxti)
    │  4. Symtable        — har nom: local, global, free, cell
    ▼
 AST + ko'rinish sohalari
    │  5. Kompilyator     — boshqaruv oqimi grafi → optimallashtiruvchi → bayt-kod
    ▼
 kod obyekti (code)       ← .pyc ga shu saqlanadi (marshal)
    │  6. Virtual mashina — baholash sikli (ceval), freymlar
    ▼
 natija
Bosqich Standart vosita Nimani ko'rsatadi
Tokenlar tokenize Leksik birliklar
AST ast.parse, ast.dump Tuzilma
Ko'rinish sohalari symtable Nom qayerga tegishli
Kod obyekti compile() Bayt-kod, konstantalar, nomlar
Bayt-kod dis Instruksiyalar (12.2-dars)
Bajarish exec(), eval() Natija

Asosiy xulosa: butun modul bajarilishdan oldin kompilyatsiya qilinadi. Shuning uchun fayl oxiridagi sintaksis xatosi birinchi qatorni ham bajartirmaydi.

2.2. Ko'rinish sohalari kompilyatsiyada aniqlanadi

symtable bosqichi har bir nom uchun qaror qabul qiladi — bu ish vaqtida emas:

python
def tashqi():
    x = 1
    def ichki():
        return x + y      # x — free (closure, 10.12-dars), y — global
    return ichki
Nom tashqi da ichki da
x local (cell) free
y — global
ichki local —

Shuning uchun 7-qismdagi UnboundLocalError paydo bo'ladi: funksiyada nomga qayerdadir qiymat berilsa, kompilyator uni butun funksiya uchun local deb belgilaydi.

Python 3.14 da symtable da __annotate__ sohalari ham ko'rinadi — annotatsiyalar dangasa hisoblanadi (PEP 649).

2.3. Kompilyatsiya xatosi va ish vaqti xatosi

Xato Qachon Misol
SyntaxError, IndentationError Kompilyatsiyada — hech narsa bajarilmaydi def f(:
Ba'zi semantik xatolar Kompilyatsiyada (symtable) nonlocal x modul darajasida, return funksiyadan tashqarida
NameError, TypeError, ... Ish vaqtida, shu qatorga yetib kelganda print(yoq_ozgaruvchi)

compile("print(yoq_ozgaruvchi)", ...) muvaffaqiyatli o'tadi — kompilyator nom mavjudligini tekshirmaydi, faqat qanday qidirishni (global) belgilaydi.

2.4. Kod obyekti

compile() va har bir def, lambda, class tanasi, comprehension — kod obyekti hosil qiladi. U o'zgarmas:

Atribut Ma'nosi
co_code Bayt-kod (baytlar)
co_consts Konstantalar: sonlar, satrlar, ichki kod obyektlari
co_names Global va atribut nomlari
co_varnames Lokal o'zgaruvchilar (parametrlar birinchi)
co_cellvars, co_freevars Closure hujayralari (10.12-dars)
co_argcount, co_kwonlyargcount, co_posonlyargcount Parametrlar soni
co_stacksize Kerakli stek chuqurligi
co_flags Generator, korutina, *args va h.k. bayroqlari
co_filename, co_name, co_qualname, co_firstlineno Joylashuv
co_lines(), co_positions() Bayt-kod ↔ manba qator va ustunlar

Funksiya ≠ kod obyekti. Funksiya = kod obyekti + __globals__ + __defaults__ + __closure__ + nom (11.6-dars). Bitta kod obyektidan ko'p funksiya yaratilishi mumkin (sikldagi def).

code.replace(...) — o'zgartirilgan nusxa (debugger, profiler va test vositalari ishlatadi).

2.5. .pyc fayllar

Qachon yoziladi: modul import qilinganda — __pycache__/modul.cpython-314.pyc. Asosiy skript (python app.py) uchun .pyc yozilmaydi.

Sarlavha (16 bayt):

Bayt Maydon
0–3 Magic raqam — Python versiyasi (importlib.util.MAGIC_NUMBER)
4–7 Bayroqlar: 0 — vaqt belgisi; 1 — xesh; 3 — xesh + manbani tekshirish
8–15 Vaqt belgisi rejimi: manba mtime va hajmi; xesh rejimi: manba xeshi (8 bayt)
16– marshal qilingan kod obyekti

Bekor qilish (invalidation) usullari:

Rejim Qanday tekshiriladi Qayerda
TIMESTAMP (sukut) Manba mtime va hajmi sarlavhadagiga tengmi Oddiy ishlab chiqish
CHECKED_HASH Manba xeshi hisoblanib solishtiriladi Qayta tiklanadigan (reproducible) yig'malar
UNCHECKED_HASH Tekshirilmaydi Tizim paketlari, o'zgarmas obrazlar

Magic raqam mos kelmasa (boshqa Python versiyasi) — .pyc e'tiborsiz qoldiriladi va qayta kompilyatsiya qilinadi.

Boshqaruv:

Vosita Ta'siri
python -m compileall papka Hammasini oldindan kompilyatsiya qilish
python -B, PYTHONDONTWRITEBYTECODE=1 .pyc yozmaslik
PYTHONPYCACHEPREFIX=/tmp/pyc Keshni boshqa papkada saqlash (faqat o'qish tizimlari uchun)

2.6. Optimallashtirish darajalari

Bayroq sys.flags.optimize Nima olib tashlanadi .pyc nomi
— 0 Hech narsa modul.cpython-314.pyc
-O 1 assert va if __debug__: bloklari .opt-1.pyc
-OO 2 Yuqoridagilar + docstringlar .opt-2.pyc

assert ni foydalanuvchi ma'lumotini tekshirish uchun ishlatmang — -O bilan u yo'qoladi (9-qism).

2.7. Virtual mashina

CPython VM — stek mashinasi: har instruksiya qiymatlar stekidan oladi va unga qo'yadi.

narx * soni          LOAD_FAST narx    stek: [narx]
                     LOAD_FAST soni    stek: [narx, soni]
                     BINARY_OP *       stek: [natija]

(Soddalashtirilgan: 3.14 da dis birlashtirilgan instruksiyalarni ko'rsatadi, masalan LOAD_FAST_BORROW_LOAD_FAST_BORROW — 12.2-dars.)

  • Har funksiya chaqiruvi — yangi freym (lokal o'zgaruvchilar, stek, joriy instruksiya) — 12.3-dars
  • Baholash sikli (ceval.c) instruksiyalarni ketma-ket bajaradi
  • 3.11+ da instruksiyalar ish vaqtida ixtisoslashadi (BINARY_OP → BINARY_OP_MULTIPLY_FLOAT) — 12.8-dars
  • 3.13+ da tajribaviy JIT kompilyator mavjud (sukut bo'yicha o'chiq)

compile rejimlari:

Rejim Kirish Natija
"exec" Modul (ko'p statement) exec() — None
"eval" Bitta ifoda eval() — qiymat
"single" Bitta interaktiv statement REPL kabi: ifoda qiymati chop etiladi

3. Tez ma'lumotnoma

Bosqichlarni ko'rish

tokenize.generate_tokens(io.StringIO(src).readline)
ast.dump(ast.parse(src), indent=2)
symtable.symtable(src, "<nom>", "exec")
code = compile(src, "<nom>", "exec" | "eval" | "single", optimize=-1|0|1|2)
dis.dis(code)          exec(code, globals_dict)

Kod obyekti

co_code co_consts co_names co_varnames co_freevars co_cellvars
co_argcount co_stacksize co_flags co_qualname co_firstlineno
co_lines() co_positions() code.replace(...)

.pyc

__pycache__/modul.cpython-314[.opt-N].pyc
sarlavha 16 bayt: magic | bayroqlar | mtime+hajm yoki xesh
python -m compileall [--invalidation-mode checked-hash] papka
-B / PYTHONDONTWRITEBYTECODE   PYTHONPYCACHEPREFIX

4. Batafsil misollar

Misol 1 — Konveyer bosqichlari

python
"""Bitta manba: tokenlar, AST, symtable ko'rinish sohalari, kod obyekti va bajarish."""

import ast
import io
import symtable
import tokenize

MANBA = '''NARX = 12_000

def hisobla(soni, chegirma=0.1):
    """Buyurtma summasi."""
    def yakuniy(qiymat):
        return qiymat * (1 - chegirma)
    return yakuniy(soni * NARX)

natija = hisobla(3)
'''

print("=== 1. Tokenlar ===")
tokenlar = list(tokenize.generate_tokens(io.StringIO(MANBA).readline))
print(f"  jami: {len(tokenlar)}")
for t in tokenlar[:9]:
    print(f"  {tokenize.tok_name[t.type]:8} {t.string!r:12} qator {t.start[0]}, ustun {t.start[1]}")
turlar = {}
for t in tokenlar:
    turlar[tokenize.tok_name[t.type]] = turlar.get(tokenize.tok_name[t.type], 0) + 1
print(f"  turlar bo'yicha: {dict(sorted(turlar.items()))}")

print("\n=== 2. AST ===")
daraxt = ast.parse(MANBA)
print(f"  modul tanasi: {[type(n).__name__ for n in daraxt.body]}")
print(f"  birinchi statement: {ast.dump(daraxt.body[0])}")
funksiya = daraxt.body[1]
print(f"  hisobla: parametrlar {[a.arg for a in funksiya.args.args]}, sukut {[ast.unparse(d) for d in funksiya.args.defaults]}")
print(f"  return ifodasi: {ast.dump(funksiya.body[-1].value)}")
print(f"  ast.unparse — daraxtdan qayta manba: {ast.unparse(funksiya.body[-1])}")

print("\n=== 3. Symtable: nom qayerga tegishli ===")


def turi(belgi):
    if belgi.is_free():
        return "free"
    if belgi.is_parameter():
        return "parametr"
    if belgi.is_global():
        return "global"
    if belgi.is_local():
        return "local"
    return "?"


def aylan(jadval, chuqurlik=0):
    if jadval.get_type() == symtable.SymbolTableType.ANNOTATION:
        return
    belgilar = ", ".join(f"{b.get_name()}:{turi(b)}" for b in jadval.get_symbols())
    print(f"  {'  ' * chuqurlik}{jadval.get_type().value} {jadval.get_name()!r}: {belgilar}")
    for bola in jadval.get_children():
        aylan(bola, chuqurlik + 1)


aylan(symtable.symtable(MANBA, "<buyurtma>", "exec"))

print("\n=== 4. Kod obyekti va bajarish ===")
kod = compile(MANBA, "<buyurtma>", "exec")
print(f"  turi: {type(kod).__name__}, co_names: {kod.co_names}")
print(f"  konstantalar: {[f'<kod {c.co_name}>' if hasattr(c, 'co_code') else c for c in kod.co_consts]}")
muhit = {}
exec(kod, muhit)
print(f"  exec dan keyin natija = {muhit['natija']}, hisobla.__code__ is ichki kod obyekti: "
      f"{muhit['hisobla'].__code__ is next(c for c in kod.co_consts if hasattr(c, 'co_code'))}")

print("\n=== 5. Kompilyatsiya va ish vaqti xatolari ===")
buzuq = "print('birinchi qator bajariladimi?')\ndef f(:\n    pass\n"
try:
    compile(buzuq, "<buzuq>", "exec")
except SyntaxError as xato:
    print(f"  SyntaxError: {xato.msg}, qator {xato.lineno} — birinchi qator ham bajarilmadi")
kod = compile("print(yoq_ozgaruvchi)", "<nom>", "exec")
print(f"  mavjud bo'lmagan nom kompilyatsiyadan o'tdi: co_names = {kod.co_names}")
try:
    exec(kod, {})
except NameError as xato:
    print(f"  ish vaqtida: NameError: {xato}")
try:
    compile("def f():\n    x = 1\n    global x\n", "<nom>", "exec")
except SyntaxError as xato:
    print(f"  symtable bosqichidagi xato: {xato.msg}")

Natijaning muhim qismi:

text
=== 1. Tokenlar ===
  jami: 55
  NAME     'NARX'       qator 1, ustun 0
  OP       '='          qator 1, ustun 5
  NUMBER   '12_000'     qator 1, ustun 7
  NEWLINE  '\n'         qator 1, ustun 13
  NL       '\n'         qator 2, ustun 0
  NAME     'def'        qator 3, ustun 0
  NAME     'hisobla'    qator 3, ustun 4
  OP       '('          qator 3, ustun 11
  NAME     'soni'       qator 3, ustun 12
  turlar bo'yicha: {'DEDENT': 2, 'ENDMARKER': 1, 'INDENT': 2, 'NAME': 17, 'NEWLINE': 7, 'NL': 2, 'NUMBER': 4, 'OP': 19, 'STRING': 1}

=== 2. AST ===
  modul tanasi: ['Assign', 'FunctionDef', 'Assign']
  birinchi statement: Assign(targets=[Name(id='NARX', ctx=Store())], value=Constant(value=12000))
  hisobla: parametrlar ['soni', 'chegirma'], sukut ['0.1']
  return ifodasi: Call(func=Name(id='yakuniy', ctx=Load()), args=[BinOp(left=Name(id='soni', ctx=Load()), op=Mult(), right=Name(id='NARX', ctx=Load()))])
  ast.unparse — daraxtdan qayta manba: return yakuniy(soni * NARX)

=== 3. Symtable: nom qayerga tegishli ===
  module 'top': NARX:global, hisobla:global, natija:global
    function 'hisobla': soni:parametr, chegirma:parametr, yakuniy:local, NARX:global
      function 'yakuniy': qiymat:parametr, chegirma:free

=== 4. Kod obyekti va bajarish ===
  turi: code, co_names: ('NARX', 'hisobla', 'natija')
  konstantalar: [12000, '<kod hisobla>', None, (0.1,)]
  exec dan keyin natija = 32400.0, hisobla.__code__ is ichki kod obyekti: True

=== 5. Kompilyatsiya va ish vaqti xatolari ===
  SyntaxError: invalid syntax, qator 2 — birinchi qator ham bajarilmadi
  mavjud bo'lmagan nom kompilyatsiyadan o'tdi: co_names = ('print', 'yoq_ozgaruvchi')
  ish vaqtida: NameError: name 'yoq_ozgaruvchi' is not defined
  symtable bosqichidagi xato: name 'x' is assigned to before global declaration

Nima ko'rsatdi: 2.1–2.3-bo'limlar.

Misol 2 — Kod obyekti anatomiyasi

python
"""Kod obyekti atributlari; funksiya va kod obyekti farqi; co_lines; code.replace; compile rejimlari va optimize darajalari."""

import dis


def buyurtma_summasi(narx, soni, *, chegirma=0.0):
    """Chegirmali summa."""
    assert soni > 0, "soni musbat bo'lsin"
    oraliq = narx * soni
    return round(oraliq * (1 - chegirma), 2)


kod = buyurtma_summasi.__code__

print("=== 1. Atributlar ===")
for nom in ["co_name", "co_qualname", "co_argcount", "co_kwonlyargcount", "co_varnames",
            "co_names", "co_consts", "co_stacksize", "co_firstlineno"]:
    print(f"  {nom:18} {getattr(kod, nom)!r}")
bayroqlar = [nom for bit, nom in dis.COMPILER_FLAG_NAMES.items() if kod.co_flags & bit]
print(f"  {'co_flags':18} {bayroqlar}")
print(f"  {'len(co_code)':18} {len(kod.co_code)} bayt")

print("\n=== 2. Bayt-kod ↔ qatorlar ===")
for bosh, oxir, qator in kod.co_lines():
    if qator is not None:
        print(f"  baytlar {bosh:>3}–{oxir:<3} → qator +{qator - kod.co_firstlineno}")

print("\n=== 3. Funksiya ≠ kod obyekti ===")
yaratilgan = []
for foiz in (5, 10):
    def chegirma(summa, foiz=foiz):
        return summa * (100 - foiz) / 100
    yaratilgan.append(chegirma)
print(f"  ikki funksiya bitta obyektmi: {yaratilgan[0] is yaratilgan[1]}, kodi bitta obyektmi: {yaratilgan[0].__code__ is yaratilgan[1].__code__}")
print(f"  farq faqat __defaults__ da: {yaratilgan[0].__defaults__}, {yaratilgan[1].__defaults__}")
nusxa = type(buyurtma_summasi)(kod, {"round": round}, "nusxa")
try:
    nusxa(100, 3)
except TypeError as xato:
    print(f"  kod obyektidan yangi funksiya, sukutlarsiz: TypeError: {xato}")
print(f"  sukutlar funksiyada, kodda emas: __kwdefaults__ {buyurtma_summasi.__kwdefaults__} va {nusxa.__kwdefaults__}")
print(f"  chegirma berilsa: {nusxa.__name__}(100, 3, chegirma=0.1) = {nusxa(100, 3, chegirma=0.1)}")

print("\n=== 4. code.replace ===")


def salomlash():
    return "Assalomu alaykum"


eski = salomlash.__code__
salomlash.__code__ = eski.replace(co_consts=tuple("Xush kelibsiz" if c == "Assalomu alaykum" else c for c in eski.co_consts))
print(f"  konstanta almashtirildi: {salomlash()}")
salomlash.__code__ = eski

print("\n=== 5. compile rejimlari ===")
print(f"  eval: {eval(compile('2 ** 10 + 24', '<e>', 'eval'))}")
muhit = {}
print(f"  exec: {exec(compile('x = 2 ** 10', '<x>', 'exec'), muhit)}, x = {muhit['x']}")
print("  single (REPL kabi, ifoda qiymatini o'zi chop etadi):")
exec(compile("2 ** 10 + 24", "<s>", "single"))
try:
    compile("x = 1", "<e>", "eval")
except SyntaxError as xato:
    print(f"  eval rejimida statement: SyntaxError: {xato.msg}")

print("\n=== 6. optimize darajalari ===")
MANBA = '''def f(soni):
    """Hujjat satri."""
    assert soni > 0
    if __debug__:
        tekshiruv = "debug"
    return soni
'''
for daraja in (0, 1, 2):
    muhit = {}
    exec(compile(MANBA, "<opt>", "exec", optimize=daraja), muhit)
    f = muhit["f"]
    try:
        f(-1)
        assert_holati = "o'chirildi"
    except AssertionError:
        assert_holati = "ishladi"
    print(f"  optimize={daraja}: bayt-kod {len(f.__code__.co_code):>2} bayt, assert {assert_holati:10}, "
          f"__doc__ {f.__doc__!r}, 'debug' konstantada: {'debug' in f.__code__.co_consts}")

Natijaning muhim qismi:

text
=== 1. Atributlar ===
  co_name            'buyurtma_summasi'
  co_qualname        'buyurtma_summasi'
  co_argcount        2
  co_kwonlyargcount  1
  co_varnames        ('narx', 'soni', 'chegirma', 'oraliq')
  co_names           ('round',)
  co_consts          ('Chegirmali summa.', "soni musbat bo'lsin")
  co_stacksize       5
  co_firstlineno     6
  co_flags           ['OPTIMIZED', 'NEWLOCALS', 'HAS_DOCSTRING']
  len(co_code)       98 bayt

=== 2. Bayt-kod ↔ qatorlar ===
  baytlar   0–2   → qator +0
  baytlar   2–30  → qator +2
  baytlar  30–46  → qator +3
  baytlar  46–98  → qator +4

=== 3. Funksiya ≠ kod obyekti ===
  ikki funksiya bitta obyektmi: False, kodi bitta obyektmi: True
  farq faqat __defaults__ da: (5,), (10,)
  kod obyektidan yangi funksiya, sukutlarsiz: TypeError: buyurtma_summasi() missing 1 required keyword-only argument: 'chegirma'
  sukutlar funksiyada, kodda emas: __kwdefaults__ {'chegirma': 0.0} va None
  chegirma berilsa: nusxa(100, 3, chegirma=0.1) = 270.0

=== 4. code.replace ===
  konstanta almashtirildi: Xush kelibsiz

=== 5. compile rejimlari ===
  eval: 1048
  exec: None, x = 1024
  single (REPL kabi, ifoda qiymatini o'zi chop etadi):
1048
  eval rejimida statement: SyntaxError: invalid syntax

=== 6. optimize darajalari ===
  optimize=0: bayt-kod 30 bayt, assert ishladi   , __doc__ 'Hujjat satri.', 'debug' konstantada: True
  optimize=1: bayt-kod  8 bayt, assert o'chirildi, __doc__ 'Hujjat satri.', 'debug' konstantada: False
  optimize=2: bayt-kod  8 bayt, assert o'chirildi, __doc__ None, 'debug' konstantada: False

Nima ko'rsatdi: 2.4, 2.6, 2.7-bo'limlar.

Misol 3 — .pyc ichidan

python
"""py_compile bilan .pyc; 16 baytli sarlavhani o'qish; marshal bilan kod obyektini tiklash; xesh rejimi; import keshni ishlatishi."""

import importlib
import importlib.util
import marshal
import pathlib
import py_compile
import struct
import sys
import tempfile

papka = pathlib.Path(tempfile.mkdtemp())
manba = papka / "narxlar.py"
manba.write_bytes(b'KURS = 12_650\n\ndef som(dollar):\n    return dollar * KURS\n\nprint("narxlar moduli bajarildi")\n')


def nisbiy(yol):
    return pathlib.Path(yol).relative_to(papka).as_posix()


print("=== 1. Kesh fayl nomi ===")
print(f"  cache_tag: {sys.implementation.cache_tag}")
print(f"  oddiy: {nisbiy(importlib.util.cache_from_source(manba))}")
print(f"  -OO:   {nisbiy(importlib.util.cache_from_source(manba, optimization=2))}")

print("\n=== 2. Sarlavha (vaqt belgisi rejimi) ===")
pyc = pathlib.Path(py_compile.compile(manba, doraise=True))
baytlar = pyc.read_bytes()
magic = baytlar[:4]
bayroqlar, mtime, hajm = struct.unpack("<III", baytlar[4:16])
print(f"  fayl: {nisbiy(pyc)}, jami {len(baytlar)} bayt")
print(f"  magic {magic!r} == MAGIC_NUMBER: {magic == importlib.util.MAGIC_NUMBER}")
print(f"  bayroqlar: {bayroqlar}, mtime mos: {mtime == int(manba.stat().st_mtime)}, hajm {hajm} == manba {manba.stat().st_size}")

print("\n=== 3. marshal: kod obyektini tiklash ===")
kod = marshal.loads(baytlar[16:])
print(f"  turi: {type(kod).__name__}, co_names: {kod.co_names}")
muhit = {"__name__": "narxlar"}
exec(kod, muhit)
print(f"  manbasiz bajarildi: som(3) = {muhit['som'](3):,}")

print("\n=== 4. Xesh rejimi ===")
pyc = pathlib.Path(py_compile.compile(manba, doraise=True, invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH))
baytlar = pyc.read_bytes()
bayroqlar = struct.unpack("<I", baytlar[4:8])[0]
print(f"  bayroqlar: {bayroqlar} (xesh: {bool(bayroqlar & 1)}, manbani tekshirish: {bool(bayroqlar & 2)})")
print(f"  sarlavhadagi xesh == source_hash(manba): {baytlar[8:16] == importlib.util.source_hash(manba.read_bytes())}")

print("\n=== 5. import keshni ishlatadi ===")
py_compile.compile(manba, doraise=True)
sys.path.insert(0, str(papka))
sys.dont_write_bytecode = False
import narxlar
print(f"  narxlar.__cached__: {nisbiy(narxlar.__cached__)}")
pyc_yol = pathlib.Path(narxlar.__cached__)
oldingi = pyc_yol.stat().st_mtime_ns
del sys.modules["narxlar"]
importlib.import_module("narxlar")
print(f"  qayta import: .pyc qayta yozilmadi — {pyc_yol.stat().st_mtime_ns == oldingi}")
pyc_yol.write_bytes(b"\x00\x00\x00\x00" + pyc_yol.read_bytes()[4:])
del sys.modules["narxlar"]
importlib.import_module("narxlar")
print(f"  buzilgan magic: Python .pyc ni e'tiborsiz qoldirib, qayta kompilyatsiya qildi — {pyc_yol.read_bytes()[:4] == importlib.util.MAGIC_NUMBER}")
sys.path.remove(str(papka))

Natijaning muhim qismi:

text
=== 1. Kesh fayl nomi ===
  cache_tag: cpython-314
  oddiy: __pycache__/narxlar.cpython-314.pyc
  -OO:   __pycache__/narxlar.cpython-314.opt-2.pyc

=== 2. Sarlavha (vaqt belgisi rejimi) ===
  fayl: __pycache__/narxlar.cpython-314.pyc, jami 370 bayt
  magic b'+\x0e\r\n' == MAGIC_NUMBER: True
  bayroqlar: 0, mtime mos: True, hajm 92 == manba 92

=== 3. marshal: kod obyektini tiklash ===
  turi: code, co_names: ('KURS', 'som', 'print')
narxlar moduli bajarildi
  manbasiz bajarildi: som(3) = 37,950

=== 4. Xesh rejimi ===
  bayroqlar: 3 (xesh: True, manbani tekshirish: True)
  sarlavhadagi xesh == source_hash(manba): True

=== 5. import keshni ishlatadi ===
narxlar moduli bajarildi
  narxlar.__cached__: __pycache__/narxlar.cpython-314.pyc
narxlar moduli bajarildi
  qayta import: .pyc qayta yozilmadi — True
narxlar moduli bajarildi
  buzilgan magic: Python .pyc ni e'tiborsiz qoldirib, qayta kompilyatsiya qildi — True

Nima ko'rsatdi: 2.5-bo'lim. Modul har importda emas, faqat birinchi va .pyc yaroqsiz bo'lganda kompilyatsiya qilinadi; "narxlar moduli bajarildi" esa har import_module da chiqdi — kompilyatsiya keshlanadi, modul kodining bajarilishi emas.

Misol 4 — Amaliy: formulalar dvigateli

Jadval ilovasida foydalanuvchi ustunlar uchun formulalar yozadi: narx * soni * (1 - chegirma). Formula har qator uchun bajariladi. Konveyerni boshqarib, uni xavfsiz va tez qilamiz: AST darajasida ruxsat etilgan tugunlarni tekshiramiz, bir marta kompilyatsiya qilamiz va kod obyektini keshlaymiz.

python
"""Formula: ast bilan tekshiruv (oq ro'yxat), compile bir marta, kesh; har qatorda eval bilan solishtirish; xavfli formulalarni rad etish."""

import ast
import math
import time
from functools import lru_cache

RUXSAT_TUGUNLAR = (ast.Expression, ast.BinOp, ast.UnaryOp, ast.Constant, ast.Name, ast.Load,
                   ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Pow, ast.Mod, ast.USub, ast.UAdd,
                   ast.Call, ast.Compare, ast.Gt, ast.Lt, ast.GtE, ast.LtE, ast.Eq, ast.IfExp)
FUNKSIYALAR = {"round": round, "min": min, "max": max, "abs": abs, "sqrt": math.sqrt}


class FormulaXatosi(ValueError):
    pass


@lru_cache(maxsize=256)
def kompilyatsiya(formula, ustunlar):
    try:
        daraxt = ast.parse(formula, mode="eval")
    except SyntaxError as xato:
        raise FormulaXatosi(f"sintaksis: {xato.msg}") from None
    for tugun in ast.walk(daraxt):
        if not isinstance(tugun, RUXSAT_TUGUNLAR):
            raise FormulaXatosi(f"ruxsat etilmagan: {type(tugun).__name__}")
        if isinstance(tugun, ast.Name) and tugun.id not in ustunlar and tugun.id not in FUNKSIYALAR:
            raise FormulaXatosi(f"noma'lum nom: {tugun.id}")
        if isinstance(tugun, ast.Call) and not (isinstance(tugun.func, ast.Name) and tugun.func.id in FUNKSIYALAR):
            raise FormulaXatosi("faqat ruxsat etilgan funksiyalar")
    return compile(daraxt, f"<formula: {formula}>", "eval")


def hisobla(formula, qatorlar):
    kod = kompilyatsiya(formula, tuple(sorted(qatorlar[0])))
    muhit = {"__builtins__": {}, **FUNKSIYALAR}
    return [eval(kod, muhit, qator) for qator in qatorlar]


QATORLAR = [{"narx": 10_000.0 + i, "soni": i % 7, "chegirma": (i % 4) * 0.05} for i in range(30_000)]
FORMULA = "round(narx * soni * (1 - chegirma), 2)"

print("=== 1. Natija ===")
natija = hisobla(FORMULA, QATORLAR)
print(f"  birinchi 4: {natija[:4]}, jami: {sum(natija):,.2f}")
print(f"  kesh: {kompilyatsiya.cache_info()}")
hisobla(FORMULA, QATORLAR[:10])
print(f"  ikkinchi chaqiruv: {kompilyatsiya.cache_info()}")

print("\n=== 2. Har qatorda manbadan eval va bir marta compile ===")


def har_safar(formula, qatorlar):
    muhit = {"__builtins__": {}, **FUNKSIYALAR}
    return [eval(formula, muhit, qator) for qator in qatorlar]


def eng_yaxshi(f, *args, takror=3):
    vaqtlar = []
    for _ in range(takror):
        bosh = time.perf_counter()
        f(*args)
        vaqtlar.append(time.perf_counter() - bosh)
    return min(vaqtlar)


sekin = eng_yaxshi(har_safar, FORMULA, QATORLAR)
tez = eng_yaxshi(hisobla, FORMULA, QATORLAR)
print(f"  natijalar teng: {har_safar(FORMULA, QATORLAR) == natija}")
print(f"  bir marta kompilyatsiya kamida 5 barobar tez: {sekin / tez > 5}")

print("\n=== 3. Xavfli va xato formulalar ===")
for yomon in ["__import__('os').system('rm -rf /')", "narx.__class__", "[x for x in range(10**9)]",
              "narx * (soni", "narx * foyda", "open('parol.txt')", "soni ** 2 if soni > 3 else -soni"]:
    try:
        kompilyatsiya(yomon, ("chegirma", "narx", "soni"))
        print(f"  ✅ {yomon!r}")
    except FormulaXatosi as xato:
        print(f"  ❌ {yomon!r}: {xato}")

Natijaning muhim qismi:

text
=== 1. Natija ===
  birinchi 4: [0.0, 9500.95, 18003.6, 25507.65], jami: 2,081,119,756.75
  kesh: CacheInfo(hits=0, misses=1, maxsize=256, currsize=1)
  ikkinchi chaqiruv: CacheInfo(hits=1, misses=1, maxsize=256, currsize=1)

=== 2. Har qatorda manbadan eval va bir marta compile ===
  natijalar teng: True
  bir marta kompilyatsiya kamida 5 barobar tez: True

=== 3. Xavfli va xato formulalar ===
  ❌ "__import__('os').system('rm -rf /')": faqat ruxsat etilgan funksiyalar
  ❌ 'narx.__class__': ruxsat etilmagan: Attribute
  ❌ '[x for x in range(10**9)]': ruxsat etilmagan: ListComp
  ❌ 'narx * (soni': sintaksis: '(' was never closed
  ❌ 'narx * foyda': noma'lum nom: foyda
  ❌ "open('parol.txt')": faqat ruxsat etilgan funksiyalar
  ✅ 'soni ** 2 if soni > 3 else -soni'

Nima ko'rsatdi: 2.1, 2.4, 2.7-bo'limlar — konveyer bosqichlarini alohida boshqarish formulani tekshirishga (AST) va bir marta kompilyatsiya qilishga imkon beradi. AST oq ro'yxati eval ni to'liq xavfsiz qilmaydi (masalan, 10 ** 10 ** 10 kabi resurs hujumlari) — ishonchsiz kod uchun alohida jarayon va cheklovlar kerak (20-qism).


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"Python kodni qatorma-qator o'qib bajaradi" Butun modul avval bayt-kodga kompilyatsiya qilinadi
"Python kompilyatsiya qilmaydi" Qiladi — mashina kodiga emas, bayt-kodga
".pyc — tezroq ishlaydigan kod" Bajarilish tezligi bir xil; faqat kompilyatsiya bosqichi o'tkazib yuboriladi
"python app.py uchun ham .pyc yoziladi" Faqat import qilingan modullar uchun
"NameError kompilyatsiyada topiladi" Ish vaqtida — kompilyator faqat qidirish usulini belgilaydi
"-O kodni tezlashtiradi" Faqat assert, __debug__ va (-OO) docstringlarni olib tashlaydi
".pyc boshqa Python versiyasida ham ishlaydi" Magic raqam mos kelmasa, e'tiborsiz qoldiriladi
"Funksiya va uning kodi — bitta narsa" Kod obyekti o'zgarmas va ulashiladi; funksiya uni muhit bilan bog'laydi

6. Keng tarqalgan xatolar va yechimlari

1. Faqat o'qish fayl tizimida .pyc siz ishga tushirish

dockerfile
COPY . /app                                     # ⚠️ har pod ishga tushishda kompilyatsiya
RUN python -m compileall -q /app                # ✅ obraz yig'ilganda

2. assert bilan kiritmani tekshirish

python
assert summa > 0, "summa musbat bo'lsin"         # ❌ -O bilan yo'qoladi
if summa <= 0:
    raise ValueError("summa musbat bo'lsin")     # ✅

3. Sikl ichida bir xil satrni eval/exec qilish

python
for qator in qatorlar:
    eval(formula, {}, qator)                     # ❌ har safar parse + compile
kod = compile(formula, "<f>", "eval")
for qator in qatorlar:
    eval(kod, {}, qator)                         # ✅

4. eval ga ishonchsiz satr berish

python
eval(request.args["formula"])                    # ❌ istalgan kod bajariladi

ast.literal_eval (faqat literallar) yoki AST oq ro'yxati + cheklangan muhit; ishonchsiz kod uchun alohida jarayon.

5. .pyc fayllarni git ga qo'shish

gitignore
__pycache__/                                     # ✅ har doim .gitignore da
*.pyc

6. Faqat .pyc tarqatib, kodni "yashirish"

bash
python -m compileall app && rm app/*.py          # ⚠️ dekompilyatorlar va dis bilan o'qiladi, versiyaga bog'liq

7. Konteynerda PYTHONDONTWRITEBYTECODE=1 va yig'ishda kompilyatsiya qilmaslik

dockerfile
ENV PYTHONDONTWRITEBYTECODE=1                    # ⚠️ o'zi yetarli emas — har ishga tushish sekin
RUN python -m compileall -q /app /usr/local/lib/python3.14   # ✅ oldindan

8. Sintaksis xatosini try bilan ushlashga urinish

python
try:
    def f(: pass                                 # ❌ butun fayl kompilyatsiyadan o'tmaydi
except SyntaxError:
    ...

Dinamik kod uchun compile() ni try ichida chaqiring.


7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 7-qism (o'tilgan): UnboundLocalError — ko'rinish sohasi kompilyatsiyada aniqlanadi
  • 10.12-dars (o'tilgan): closure — co_freevars, co_cellvars
  • 11.6-dars (o'tilgan): funksiya obyekti va __defaults__
  • 11.7-dars (o'tilgan): konstantalarni oldindan hisoblash — kompilyator optimallashtiruvchisi
  • 12.2-dars: dis bilan bayt-kodni o'qish
  • 12.3-dars: freym va chaqiruv steki
  • 12.8-dars: ixtisoslashgan adaptiv interpretator
  • 19-qism: paketlash — .pyc, compileall, wheel
  • 28-qism: Docker obrazlarida ishga tushish vaqtini optimallashtirish

8. Eng yaxshi amaliyotlar

  1. Production obrazlarida python -m compileall — ayniqsa faqat o'qish fayl tizimlarida.

  2. __pycache__ va *.pyc — .gitignore da.

  3. Dinamik kodni bir marta compile qiling, kod obyektini qayta ishlating.

  4. Ishonchsiz ifodalar uchun AST tekshiruvi yoki ast.literal_eval.

  5. assert — faqat dasturchi farazlari uchun.

  6. Kod tahlili vositalari uchun ast, symtable, tokenize — regex bilan manba tahlil qilmang.

  7. Qayta tiklanadigan yig'malarda --invalidation-mode checked-hash.

  8. Ishga tushish sekin bo'lsa, python -X importtime bilan o'lchang (18-qism).


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
import ast
1.  kod = compile("1 + 2", "<t>", "eval")
    print(eval(kod))
2.  print(type(compile("x = 1", "<t>", "exec")).__name__)
3.  try:
        compile("x = 1", "<t>", "eval")
    except SyntaxError:
        print("SyntaxError")
4.  kod = compile("print(nomalum)", "<t>", "exec")
    print("kompilyatsiya bo'ldi")
5.  print(type(ast.parse("a + b").body[0]).__name__)
6.  print(type(ast.parse("a + b", mode="eval").body).__name__)
7.  def f(a, b=2, *, c=3):
        d = a + b
        return d
    print(f.__code__.co_argcount, f.__code__.co_kwonlyargcount)
8.  print(f.__code__.co_varnames)
9.  fs = [lambda: 1 for _ in range(2)]
    print(fs[0] is fs[1], fs[0].__code__ is fs[1].__code__)
10. m = {}
    exec(compile('def g():\n    """doc"""\n    return 1', "<t>", "exec", optimize=2), m)
    print(m["g"].__doc__)
11. print(ast.unparse(ast.parse("x=(1+2)*3")))
12. exec(compile("5 * 5", "<t>", "single"))
Javoblar
  1. 3
  2. code
  3. SyntaxError — eval rejimi faqat ifoda qabul qiladi
  4. kompilyatsiya bo'ldi — nom ish vaqtida qidiriladi
  5. Expr
  6. BinOp — Expression.body to'g'ridan-to'g'ri ifoda
  7. 2 1
  8. ('a', 'b', 'c', 'd') — parametrlar birinchi, keyin lokallar
  9. False True — ikki funksiya, bitta kod obyekti
  10. None — optimize=2 docstringni olib tashladi
  11. x = (1 + 2) * 3
  12. 25 — single rejimi ifoda qiymatini chop etadi

Vazifa 2: Xatolarni tuzating

python
1.  def filtrla(yozuvlar, shart):
        return [y for y in yozuvlar if eval(shart, {}, y)]

2.  def yosh_tekshir(yosh):
        assert 0 < yosh < 150, "noto'g'ri yosh"
        return yosh

3.  def sozlama_oqi(matn):
        return eval(matn)          # "{'port': 8080, 'debug': True}"

4.  # Dockerfile
    FROM python:3.14-slim
    ENV PYTHONDONTWRITEBYTECODE=1
    COPY app /app
    CMD ["python", "-m", "app"]

5.  try:
        import yangi_modul
    except SyntaxError:
        yangi_modul = None
Javoblar
python
1.  def filtrla(yozuvlar, shart):
        kod = compile(shart, "<shart>", "eval")          # bir marta
        return [y for y in yozuvlar if eval(kod, {"__builtins__": {}}, y)]

2.  def yosh_tekshir(yosh):
        if not 0 < yosh < 150:
            raise ValueError("noto'g'ri yosh")           # -O bilan yo'qolmaydi
        return yosh

3.  import ast
    def sozlama_oqi(matn):
        return ast.literal_eval(matn)                    # faqat literallar, kod bajarilmaydi

4.  FROM python:3.14-slim
    ENV PYTHONDONTWRITEBYTECODE=1
    COPY app /app
    RUN python -m compileall -q /app                     # obraz yig'ilganda kompilyatsiya
    CMD ["python", "-m", "app"]

5.  # Bu kod to'g'ri: import qilinayotgan modulning SyntaxError i shu faylni emas,
    # import paytidagi kompilyatsiyani buzadi va ushlanadi. Lekin xatoni yashirmaslik uchun:
    try:
        import yangi_modul
    except SyntaxError as xato:
        log.error("yangi_modul buzilgan: %s", xato)
        raise

Vazifa 3: Konveyer ko'ruvchi

konveyer.py CLI vositasini yozing (argparse, 15-qism):

  1. python konveyer.py fayl.py --bosqich tokens|ast|symtable|code|dis
  2. tokens — turlar bo'yicha statistika va birinchi N token
  3. ast — ast.dump(indent=2) va tugun turlari soni
  4. symtable — har funksiya uchun local/global/free/cell nomlar jadvali
  5. code — barcha ichki kod obyektlari daraxti: nom, qator, bayt-kod hajmi, konstantalar soni

Vazifa 4: .pyc inspektori

pyc_info(yol) funksiyasini yozing:

  1. Sarlavhani o'qib, rejim (vaqt belgisi / tekshiriladigan xesh / tekshirilmaydigan xesh) va Python versiyasini (magic raqamdan) aniqlasin
  2. Manba fayl mavjud bo'lsa, .pyc yaroqliligini tekshirsin
  3. Kod obyektlari daraxtidagi barcha funksiyalar ro'yxatini chiqarsin
  4. compileall bilan loyihangizning __pycache__ papkasiga qo'llang va eskirgan .pyc larni toping

Vazifa 5: Sintaksis kengaytmasi

ast.NodeTransformer (10-qism bilan bog'lang) yordamida "import hook" siz transformator yozing:

  1. x |> f |> g o'rniga ozgartir("x |> f", ...) kabi funksiya: manbadagi >> operatorini g(f(x)) chaqiruviga aylantiradi (ast.BinOp va ast.RShift)
  2. Qator raqamlarini ast.copy_location bilan saqlasin — traceback to'g'ri qatorni ko'rsatsin
  3. compile va exec bilan bajarsin
  4. Transformatsiyadan oldingi va keyingi manbani ast.unparse bilan ko'rsating

Vazifa 6: Ishga tushish vaqti

Katta bog'liqliklarga ega loyiha (yoki 200 ta sun'iy modul yarating) uchun:

  1. .pyc siz (-B, keshni tozalab) va .pyc bilan import vaqtini time.perf_counter bilan o'lchang
  2. python -X importtime natijasini tahlil qilib, eng sekin 10 modulni chiqaring
  3. PYTHONPYCACHEPREFIX bilan faqat o'qish papkasini simulyatsiya qiling
  4. Natijani jadvalda ko'rsating va Docker uchun tavsiya yozing

Vazifa 7: O'ylash

Java kodni .class bayt-kodga kompilyatsiya qilib, JVM da JIT bilan bajaradi; Go va Rust to'g'ridan-to'g'ri mashina kodiga kompilyatsiya qiladi; JavaScript dvigatellari (V8) manbadan ish vaqtida bayt-kod va keyin JIT orqali mashina kodi yaratadi. CPython qaysi modelga yaqin, uning "kompilyatsiya" si Java'nikidan nimasi bilan farq qiladi va bu farq ishga tushish vaqti, tarqatish va xatolarni topishga qanday ta'sir qiladi?

Javob

Qisqa javob: CPython modeli Java va V8 o'rtasida: Java kabi alohida bayt-kod bosqichi va keshlangan fayl (.pyc ↔ .class) bor, lekin kompilyatsiya dasturchi tomonidan emas, import paytida avtomatik va deyarli hech qanday tekshiruvsiz bajariladi. Bayt-kod mashina kodiga emas, interpretatorda bajariladi (3.13+ tajribaviy JIT bundan mustasno). Natijada ishga tushish tez va tarqatish oddiy, lekin turlar va nomlar xatolari faqat ish vaqtida chiqadi.

1. Modellar

Til Kompilyatsiya Bajarilish Tur tekshiruvi
C, Go, Rust Oldindan → mashina kodi To'g'ridan-to'g'ri CPU Kompilyatsiyada
Java, C# Oldindan (javac) → bayt-kod JVM: interpretator + JIT Kompilyatsiyada
JavaScript (V8) Ish vaqtida → bayt-kod (Ignition) Interpretator + JIT (Maglev, TurboFan) Yo'q
CPython Import paytida → bayt-kod (.pyc) Interpretator (3.11+ ixtisoslashuv, 3.13+ tajribaviy JIT) Yo'q (faqat tashqi vositalar)

2. Java bilan farq

  • javac alohida qadam: turlar, nomlar, imzolar tekshiriladi — xatolar ishga tushishdan oldin topiladi
  • CPython kompilyatori faqat sintaksis va ko'rinish sohalarini tekshiradi; nomalum() va 1 + "a" kompilyatsiyadan o'tadi
  • Java bayt-kodi tipli (iadd, dadd), CPython bayt-kodi umumiy (BINARY_OP) — turni ish vaqtida aniqlaydi va 3.11+ da bunga moslashadi (ixtisoslashuv)
  • .class fayllar — tarqatish birligi (JAR); .pyc — shunchaki kesh, manba bilan birga tarqatiladi

3. V8 bilan o'xshashlik

  • Ikkalasi ham manbadan avtomatik bayt-kod yaratadi va turlar haqida ish vaqtida ma'lumot yig'adi
  • V8 bu ma'lumot bilan agressiv JIT qiladi; CPython 3.11+ adaptiv interpretatori shu yo'lning birinchi qadami (12.8-dars)

4. Ta'siri

Jihat CPython oqibati
Ishga tushish Kompilyatsiya tez, .pyc bilan yanada tez; lekin import qilinadigan modul kodi bajariladi — og'ir importlar ishga tushishni sekinlashtiradi
Tarqatish Manba + (ixtiyoriy) .pyc; Python versiyasiga bog'liq; bitta binar fayl yo'q (PyInstaller, Nuitka — alohida vositalar)
Xatolarni topish Faqat sintaksis oldindan; qolgani — testlar, mypy/pyright (13-qism), ruff (18-qism)
Tezlik Interpretator narxi — hisoblash og'ir qismlar C kengaytmalar (NumPy) yoki boshqa tillarga (30-qism)
Moslashuvchanlik exec, eval, compile, AST transformatsiyalari — ish vaqtida kod yaratish oson

5. Xulosa

  1. CPython kompilyatsiya qiladi, lekin bayt-kodga va import paytida avtomatik
  2. Java'dan farqi: tur tekshiruvi yo'q, bayt-kod tipsiz, .pyc — tarqatish birligi emas, kesh
  3. V8 ga yaqin: ish vaqtida tur ma'lumotiga moslashish (ixtisoslashuv, JIT)
  4. Amalda: ishga tushish uchun compileall, xatolar uchun statik tahlil va testlar, tezlik uchun C kengaytmalar

Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.


Xulosa

Bu darsda Python kodining bajarilish konveyerini o'rgandik.

Eng muhim uch fikr:

  1. CPython avval kompilyatsiya qiladi, keyin bajaradi. Manba tokenlarga, tokenlar PEG parser orqali AST ga aylanadi, symtable har nomning ko'rinish sohasini (local, global, free, cell) belgilaydi, kompilyator esa optimallashtirilgan bayt-kodli kod obyekti yaratadi. Butun modul bajarilishdan oldin kompilyatsiya qilinadi: sintaksis xatosi birinchi qatorni ham bajartirmaydi, NameError esa faqat ish vaqtida chiqadi.

  2. Kod obyekti — o'zgarmas bajarish birligi. co_code, co_consts, co_names, co_varnames, co_freevars, co_lines() — hammasi unda. Funksiya kod obyektini global muhit, sukut qiymatlar va closure bilan bog'laydi; bitta kod obyektidan ko'p funksiya yaratilishi mumkin. Dinamik kodni bir marta compile qilib, kod obyektini qayta ishlatish — eval ni o'nlab barobar tezlashtiradi.

  3. .pyc — kompilyatsiya keshi, tezroq kod emas. Import qilingan modul __pycache__/modul.cpython-314.pyc ga yoziladi: 16 baytli sarlavha (magic, bayroqlar, mtime+hajm yoki xesh) va marshal qilingan kod obyekti. Faqat o'qish fayl tizimlarida compileall ni obraz yig'ish bosqichida bajaring; -O/-OO faqat assert, __debug__ va docstringlarni olib tashlaydi.

Keyingi darsda bayt-kodning o'zini o'qishni o'rganamiz: dis moduli, instruksiyalar va ularning argumentlari, stek effekti, sikllar, shartlar va funksiya chaqiruvlari bayt-kodda qanday ko'rinishi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
12.1-dars: Kod qanday bajariladi: manba → bytecode → VM — IlmHamroh