IlmHamroh
Python kursi/CPython ichki tuzilishi2/8-dars26 daqiqa
Mundarija (22)

12.2-dars: dis moduli bilan bytecode o'qish

12-QISM — CPYTHON ICHKI TUZILISHI · 2-dars


1. Kirish va motivatsiya

12.1-darsda kod obyekti ichida co_code — bayt-kod borligini ko'rdik. Endi uni o'qishni o'rganamiz.

Real vaziyat. To'lov servisida har tranzaksiyadan keyin self.jami += summa bajariladi, hisoblash bir nechta ipda (thread) ketadi. Oy oxirida hisobot bazadagi yig'indidan 0.02% kam chiqdi. Kod ko'rib chiqishda hamma "+= bitta amal-ku" dedi. dis bilan qaralganda:

LOAD_FAST        self
LOAD_ATTR        jami        ← 1. o'qish
LOAD_FAST        summa
BINARY_OP        +=          ← 2. qo'shish
...
STORE_ATTR       jami        ← 3. yozish

Uch alohida qadam. Ikki ip bir vaqtda jami ni o'qib, har biri o'z natijasini yozsa — bitta qo'shish yo'qoladi. Interpretator iplarni instruksiyalar orasida almashtirishi mumkin. Tuzatish — threading.Lock (14-qism). Muammoni esa dis ko'rsatdi.

dis — "Python aslida nima qilyapti" savoliga eng aniq javob beradigan vosita: nega x in [1, 2, 3] tez, nega lokal o'zgaruvchi globaldan tez, nega try bloki "tekin", comprehension o'z funksiyasini yaratadimi — hammasi bayt-kodda ko'rinadi.

Bu darsda:

  • dis.dis, dis.get_instructions, Instruction maydonlari
  • Chiqishni o'qish: qator, yorliq, instruksiya, argument
  • Asosiy instruksiya oilalari: yuklash/saqlash, amallar, taqqoslash, sakrashlar, chaqiruvlar
  • Stek effekti va co_stacksize
  • Shartlar, sikllar, and/or bayt-kodda
  • Istisnolar jadvali — "nol narxli" try
  • Comprehension inlining (3.12+) va generator ifodalari
  • Amaliy: bayt-kod asosidagi kod tekshiruvchi

2. Nazariya — chuqur tushuntirish

2.1. dis API

python
import dis

dis.dis(funksiya)                         # chop etish
dis.dis(funksiya, adaptive=True)          # ixtisoslashgan ko'rinish (12.8-dars)
dis.get_instructions(funksiya)            # Instruction obyektlari iteratori
dis.Bytecode(funksiya)                    # iteratsiya + .dis() + .info()
dis.code_info(funksiya)                   # kod obyekti xulosasi
dis.stack_effect(opcode, oparg)           # instruksiya stekni qanchaga o'zgartiradi
dis.opmap["BINARY_OP"], dis.opname[n]     # nom ↔ raqam

Instruction maydonlari:

Maydon Ma'nosi
opname, opcode Instruksiya nomi va raqami
arg Raqamli argument (indeks, bayroq)
argval Argumentning ma'nosi: nom, konstanta, sakrash manzili
argrepr Chop etiladigan ko'rinish
offset Bayt-koddagi o'rni
line_number, starts_line Manba qatori, shu qatorning birinchi instruksiyasimi
positions Qator va ustunlar (xato xabarlaridagi ^^^^ shundan)
is_jump_target, jump_target Sakrash manzili
baseopname Ixtisoslashgan instruksiyaning asosiy nomi

2.2. Chiqishni o'qish

  3           LOAD_FAST_BORROW_LOAD_FAST_BORROW 1 (narx, soni)
              BINARY_OP                5 (*)
              STORE_FAST               2 (jami)

  4           LOAD_FAST_BORROW         2 (jami)
              LOAD_CONST               0 (1000)
              COMPARE_OP             148 (bool(>))
              POP_JUMP_IF_FALSE       10 (to L1)
  │   │       │                        │   │
  │   │       instruksiya          arg   argrepr
  │   yorliq (sakrash manzili: L1:)
  manba qatori

Bayt-kod barqaror API emas — har Python versiyasida instruksiyalar o'zgaradi. Bu dars 3.14 bo'yicha; tamoyillar esa saqlanadi.

2.3. Instruksiya oilalari

Yuklash va saqlash:

Instruksiya Nima qiladi
LOAD_FAST, STORE_FAST Lokal o'zgaruvchi — massivdan indeks bo'yicha (tez)
LOAD_FAST_BORROW (3.14) Havolalar sanog'ini oshirmasdan yuklash — xavfsiz bo'lgan joyda
LOAD_GLOBAL Global, keyin builtins lug'atidan qidirish
LOAD_NAME, STORE_NAME Modul/klass darajasida — lug'at
LOAD_DEREF, STORE_DEREF Closure hujayrasi (10.12-dars)
LOAD_ATTR, STORE_ATTR Atribut; (nom + NULL|self) — metod chaqiruviga tayyorlash
LOAD_CONST, LOAD_SMALL_INT Konstanta; kichik son (3.14)

Birlashtirilgan (super) instruksiyalar: LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST — ikki instruksiya bittada, sikl tezroq.

Amallar va taqqoslash:

Instruksiya Manba
BINARY_OP + - * / // % ** << >> & | ^ @, += kabi, 3.14 da obj[kalit] ham
UNARY_NEGATIVE, UNARY_INVERT, UNARY_NOT -x, ~x, not x
COMPARE_OP < <= == != > >=; bool(...) — natija darhol bool sifatida kerak
IS_OP, CONTAINS_OP is/is not, in/not in
TO_BOOL Qiymatni shart uchun bool ga aylantirish

Boshqaruv oqimi:

Instruksiya Ma'nosi
POP_JUMP_IF_FALSE / _TRUE / _NONE / _NOT_NONE Shartli sakrash
JUMP_FORWARD, JUMP_BACKWARD Shartsiz sakrash (sikl boshiga — orqaga)
NOT_TAKEN (3.14) Tarmoq kuzatuvi uchun belgi, hech narsa qilmaydi
GET_ITER, FOR_ITER, END_FOR, POP_ITER for sikli
RETURN_VALUE, RESUME Qaytish; funksiya boshi/davomi nuqtasi

Qurish va chaqirish:

Instruksiya Manba
BUILD_LIST, BUILD_TUPLE, BUILD_MAP, BUILD_SET Literallar
BUILD_STRING, FORMAT_SIMPLE, FORMAT_WITH_SPEC f-string
CALL n n argumentli chaqiruv
MAKE_FUNCTION def/lambda — kod obyektidan funksiya
LIST_APPEND, SET_ADD, MAP_ADD Comprehension ichida

2.4. Stek effekti

VM — stek mashinasi (12.1-dars). Har instruksiya stekdan oladi va qo'yadi:

x and y or 0
                        stek
LOAD_FAST x             [x]                +1
COPY 1                  [x, x]             +1
TO_BOOL                 [x, bool(x)]        0
POP_JUMP_IF_FALSE L1    [x]                -1   ← yolg'on bo'lsa: x qoladi
POP_TOP                 []                 -1
LOAD_FAST y             [y]                +1
...

Kompilyator bu effektlarni yig'ib, eng chuqur holatni hisoblaydi — co_stacksize. Freym (12.3-dars) aynan shuncha joy ajratadi.

2.5. Shartlar va sikllar

Manba Bayt-kod naqshi
if shart: shart → POP_JUMP_IF_FALSE blokdan keyinga
a and b COPY, TO_BOOL, POP_JUMP_IF_FALSE — qisqa tutashuv: a yolg'on bo'lsa b hisoblanmaydi, natija — a ning o'zi
while shart: shart → POP_JUMP_IF_FALSE chiqishga; tana; JUMP_BACKWARD shartga
for x in it: GET_ITER; FOR_ITER (tugasa — END_FOR ga); STORE_FAST x; tana; JUMP_BACKWARD
break Sikldan keyingi joyga sakrash (else ni chetlab)
x in [1, 2, 3] Ro'yxat → kortej konstanta (LOAD_CONST (1, 2, 3))
x in {1, 2, 3} To'plam → frozenset konstanta

2.6. Istisnolar jadvali

Python 3.11 dan boshlab try bloki uchun hech qanday instruksiya bajarilmaydi — "nol narxli istisnolar" (zero-cost exceptions):

  22           NOP                          ← try: — hech narsa
  23   L1:     LOAD_FAST d
               LOAD_CONST 'a'
               BINARY_OP []                 ← d["a"]
       L2:     RETURN_VALUE

  --   L3:     PUSH_EXC_INFO                ← faqat istisno bo'lganda shu yerga
  24           LOAD_GLOBAL KeyError
               CHECK_EXC_MATCH
               ...
ExceptionTable:
  L1 to L2 -> L3 [0]                        ← "L1–L2 oralig'ida istisno bo'lsa, L3 ga o't"

Istisno bo'lganda interpretator co_exceptiontable dan joriy offsetni qidiradi. Oqibat: istisno bo'lmasa try deyarli tekin; istisno bo'lsa — nisbatan qimmat (traceback, jadval qidiruvi, obyekt yaratish). Shuning uchun "kamdan-kam holatlar uchun istisno" (EAFP) Python'da tabiiy (9-qism).

with ham shu mexanizmda: LOAD_SPECIAL __enter__/__exit__ va istisnolar jadvali.

2.7. Comprehension va generator ifodalari

PEP 709 (3.12+): list/set/dict comprehensionlar funksiya ichiga joylashtiriladi (inlining) — alohida kod obyekti va chaqiruv yo'q:

LOAD_FAST_AND_CLEAR  n       ← tashqi n ni vaqtincha saqlash
BUILD_LIST 0
FOR_ITER ...
LIST_APPEND 2
...
STORE_FAST n                 ← tashqi n qaytariladi

Generator ifodasi (sum(x*x for x in ...)) esa hali ham alohida kod obyekti va MAKE_FUNCTION — chunki u to'xtab-davom etadigan obyekt (10.3-dars).

2.8. dis bilan savollarga javob

Savol Bayt-kodda nima ko'rinadi
x += 1 atomarmi? O'qish, BINARY_OP, yozish — uch qadam
Nega lokal nom globaldan tez? LOAD_FAST — indeks; LOAD_GLOBAL — lug'at(lar) qidiruvi
a, b = b, a kortej yaratadimi? Yo'q: LOAD_FAST_LOAD_FAST + STORE_FAST_STORE_FAST
x in [1, 2, 3] har safar ro'yxat quradimi? Yo'q: kortej konstanta
obj.metod() bog'langan metod obyekti yaratadimi? Yo'q: LOAD_ATTR (metod + NULL|self) + CALL
try sekinlashtiradimi? Istisnosiz yo'lda — NOP

3. Tez ma'lumotnoma

API

dis.dis(f[, adaptive=True, show_caches=True])
for i in dis.get_instructions(f): i.opname, i.argval, i.argrepr, i.offset, i.line_number
dis.Bytecode(f).info()     dis.stack_effect(op, arg)     f.__code__.co_exceptiontable

Oilalar

LOAD_/STORE_ FAST(_BORROW) GLOBAL NAME DEREF ATTR CONST SMALL_INT
BINARY_OP  COMPARE_OP  IS_OP  CONTAINS_OP  TO_BOOL  UNARY_*
POP_JUMP_IF_*  JUMP_FORWARD/BACKWARD  GET_ITER FOR_ITER END_FOR
CALL  MAKE_FUNCTION  BUILD_*  FORMAT_SIMPLE  RETURN_VALUE  RESUME
PUSH_EXC_INFO CHECK_EXC_MATCH RERAISE + ExceptionTable

Naqshlar

x += 1          → 3 qadam (atomar emas)
x in [..]       → kortej konstanta;  x in {..} → frozenset
a, b = b, a     → super-instruksiyalar, kortej yo'q
[.. for ..]     → inlining (3.12+);  (.. for ..) → alohida kod obyekti
try             → NOP + istisnolar jadvali

4. Batafsil misollar

Misol 1 — O'z dis jadvalimiz: stek chuqurligi bilan

python
"""get_instructions bilan jadval: nisbiy qator, yorliq, instruksiya, argument, stek effekti va chuqurligi; Instruction maydonlari."""

import dis
import types


def argument(i):
    if isinstance(i.argval, types.CodeType):
        return f"<kod {i.argval.co_name}>"
    if i.argrepr:
        return i.argrepr
    return "" if i.arg is None else str(i.argval)


def jadval(funksiya):
    kod = funksiya.__code__
    chuqurlik = eng_chuqur = 0
    print(f"  {'qator':>5} {'offset':>6}  {'instruksiya':34} {'argument':18} {'effekt':>6} {'stek':>4}")
    for i in dis.get_instructions(funksiya):
        effekt = dis.stack_effect(i.opcode, i.arg, jump=False) if i.opcode >= dis.HAVE_ARGUMENT else dis.stack_effect(i.opcode, jump=False)
        chuqurlik += effekt
        eng_chuqur = max(eng_chuqur, chuqurlik)
        qator = f"+{i.line_number - kod.co_firstlineno}" if i.starts_line else ""
        yorliq = "→" if i.is_jump_target else " "
        print(f"  {qator:>5} {i.offset:>6} {yorliq}{i.opname:34} {argument(i):18} {effekt:>+6} {chuqurlik:>4}")
    print(f"  simulyatsiya: eng chuqur {eng_chuqur}, co_stacksize {kod.co_stacksize}")


def buyurtma(narx, soni):
    jami = narx * soni
    if jami > 1_000_000:
        jami = jami * 0.9
    return round(jami, 2)


print("=== 1. buyurtma() ===")
jadval(buyurtma)

print("\n=== 2. Bitta Instruction ===")
i = next(i for i in dis.get_instructions(buyurtma) if i.opname == "COMPARE_OP")
for maydon in ["opname", "opcode", "arg", "argval", "argrepr", "offset", "is_jump_target", "baseopname"]:
    print(f"  {maydon:15} {getattr(i, maydon)!r}")
print(f"  {'positions':15} qator +{i.positions.lineno - buyurtma.__code__.co_firstlineno}, ustunlar {i.positions.col_offset}–{i.positions.end_col_offset}")
manba_qatori = "    if jami > 1_000_000:"
print(f"  ustunlar manbada: {manba_qatori[i.positions.col_offset:i.positions.end_col_offset]!r}")

print("\n=== 3. opcode jadvali ===")
print(f"  jami instruksiya nomlari: {len(dis.opmap)}, argumentli chegara HAVE_ARGUMENT = {dis.HAVE_ARGUMENT}")
print(f"  BINARY_OP raqami {dis.opmap['BINARY_OP']}, 3.14 dagi LOAD_FAST_BORROW bor: {'LOAD_FAST_BORROW' in dis.opmap}")
print(f"  bayt-kod hajmi: {len(buyurtma.__code__.co_code)} bayt, instruksiyalar: {len(list(dis.get_instructions(buyurtma)))}")
print("  (har instruksiya 2 bayt + ba'zilari uchun ixtisoslashuv keshlari)")

Natijaning muhim qismi:

text
=== 1. buyurtma() ===
  qator offset  instruksiya                        argument           effekt stek
     +0      0  RESUME                             0                      +0    0
     +1      2  LOAD_FAST_BORROW_LOAD_FAST_BORROW  narx, soni             +2    2
             4  BINARY_OP                          *                      -1    1
            16  STORE_FAST                         jami                   -1    0
     +2     18  LOAD_FAST_BORROW                   jami                   +1    1
            20  LOAD_CONST                         1000000                +1    2
            22  COMPARE_OP                         bool(>)                -1    1
            26  POP_JUMP_IF_FALSE                  to L1                  -1    0
            30  NOT_TAKEN                                                 +0    0
     +3     32  LOAD_FAST_BORROW                   jami                   +1    1
            34  LOAD_CONST                         0.9                    +1    2
            36  BINARY_OP                          *                      -1    1
            48  STORE_FAST                         jami                   -1    0
     +4     50 →LOAD_GLOBAL                        round + NULL           +2    2
            60  LOAD_FAST_BORROW                   jami                   +1    3
            62  LOAD_SMALL_INT                     2                      +1    4
            64  CALL                               2                      -3    1
            72  RETURN_VALUE                                              +0    1
  simulyatsiya: eng chuqur 4, co_stacksize 4

=== 2. Bitta Instruction ===
  opname          'COMPARE_OP'
  opcode          56
  arg             148
  argval          '>'
  argrepr         'bool(>)'
  offset          22
  is_jump_target  False
  baseopname      'COMPARE_OP'
  positions       qator +2, ustunlar 7–23
  ustunlar manbada: 'jami > 1_000_000'

=== 3. opcode jadvali ===
  jami instruksiya nomlari: 154, argumentli chegara HAVE_ARGUMENT = 43
  BINARY_OP raqami 44, 3.14 dagi LOAD_FAST_BORROW bor: True
  bayt-kod hajmi: 74 bayt, instruksiyalar: 18
  (har instruksiya 2 bayt + ba'zilari uchun ixtisoslashuv keshlari)

Nima ko'rsatdi: 2.1–2.4-bo'limlar. positions ustunlari aynan jami > 1_000_000 ni belgiladi — traceback'dagi ^^^^ belgilari shu ma'lumotdan.

Misol 2 — Boshqaruv oqimi va istisnolar

python
"""if/and/or, while-else va break, for, try/except/finally va with — bayt-kod naqshlari va istisnolar jadvali."""

import dis
import types


def qisqa(funksiya, faqat=None):
    natija = []
    for i in dis.get_instructions(funksiya):
        if i.opname in ("RESUME", "NOT_TAKEN", "CACHE"):
            continue
        if faqat and not any(i.opname.startswith(f) for f in faqat):
            continue
        arg = f"<kod {i.argval.co_name}>" if isinstance(i.argval, types.CodeType) else i.argrepr
        natija.append(f"{'→' if i.is_jump_target else ''}{i.opname}{f'({arg})' if arg else ''}")
    return natija


def mantiq(x, y):
    return x and y or "sukut"


def qidir(sonlar, maqsad):
    i = 0
    while i < len(sonlar):
        if sonlar[i] == maqsad:
            break
        i += 1
    else:
        return -1
    return i


def yig(royxat):
    s = 0
    for x in royxat:
        s += x
    return s


def xavfsiz_bolish(a, b):
    try:
        natija = a / b
    except ZeroDivisionError:
        natija = None
    finally:
        tugadi = True
    return natija, tugadi


def oqi(yol):
    with open(yol) as f:
        return f.read()


print("=== 1. x and y or 'sukut' ===")
print(f"  {' → '.join(qisqa(mantiq))}")
for x, y in [(0, 5), (3, 0), (3, 5)]:
    print(f"  mantiq({x}, {y}) = {mantiq(x, y)!r}")

print("\n=== 2. while ... else + break ===")
print(f"  sakrashlar: {qisqa(qidir, faqat=['POP_JUMP', 'JUMP'])}")
print(f"  qidir([4, 7, 9], 7) = {qidir([4, 7, 9], 7)}, qidir([4, 7, 9], 8) = {qidir([4, 7, 9], 8)}")

print("\n=== 3. for ===")
print(f"  {' → '.join(qisqa(yig))}")

print("\n=== 4. try/except/finally ===")
kod = xavfsiz_bolish.__code__
oddiy_yol = []
for i in dis.get_instructions(xavfsiz_bolish):
    if i.opname == "PUSH_EXC_INFO":
        break
    if i.opname not in ("RESUME", "CACHE"):
        oddiy_yol.append(i.opname)
print(f"  istisnosiz yo'l: {oddiy_yol}")
print(f"  try: o'rnida faqat NOP: {oddiy_yol[0] == 'NOP'}, istisnosiz yo'lda ishlovchi instruksiyalari yo'q: "
      f"{not any(op in oddiy_yol for op in ('PUSH_EXC_INFO', 'CHECK_EXC_MATCH'))}")
print(f"  co_exceptiontable: {len(kod.co_exceptiontable)} bayt")
jadval = dis.Bytecode(xavfsiz_bolish).dis().split("ExceptionTable:")[1].strip().splitlines()
print(f"  jadval yozuvlari: {len(jadval)}, birinchisi: {jadval[0].strip()}")
print(f"  istisno bo'lsa ishlaydigan qism: {qisqa(xavfsiz_bolish, faqat=['PUSH_EXC', 'CHECK_EXC', 'POP_EXCEPT', 'RERAISE'])}")

print("\n=== 5. with ===")
print(f"  {qisqa(oqi, faqat=['LOAD_SPECIAL', 'CALL', 'PUSH_EXC', 'WITH'])}")
print(f"  istisnolar jadvali ham bor: {len(oqi.__code__.co_exceptiontable) > 0}")

Natijaning muhim qismi:

text
=== 1. x and y or 'sukut' ===
  LOAD_FAST(x) → COPY → TO_BOOL → POP_JUMP_IF_FALSE(to L1) → POP_TOP → LOAD_FAST(y) → COPY → TO_BOOL → POP_JUMP_IF_TRUE(to L2) → →POP_TOP → LOAD_CONST('sukut') → →RETURN_VALUE
  mantiq(0, 5) = 'sukut'
  mantiq(3, 0) = 'sukut'
  mantiq(3, 5) = 5

=== 2. while ... else + break ===
  sakrashlar: ['POP_JUMP_IF_FALSE(to L3)', 'POP_JUMP_IF_FALSE(to L2)', 'JUMP_BACKWARD(to L1)']
  qidir([4, 7, 9], 7) = 1, qidir([4, 7, 9], 8) = -1

=== 3. for ===
  LOAD_SMALL_INT → STORE_FAST(s) → LOAD_FAST_BORROW(royxat) → GET_ITER → →FOR_ITER(to L2) → STORE_FAST(x) → LOAD_FAST_BORROW_LOAD_FAST_BORROW(s, x) → BINARY_OP(+=) → STORE_FAST(s) → JUMP_BACKWARD(to L1) → →END_FOR → POP_ITER → LOAD_FAST_BORROW(s) → RETURN_VALUE

=== 4. try/except/finally ===
  istisnosiz yo'l: ['NOP', 'LOAD_FAST_BORROW_LOAD_FAST_BORROW', 'BINARY_OP', 'STORE_FAST', 'LOAD_CONST', 'STORE_FAST', 'LOAD_FAST_BORROW_LOAD_FAST_BORROW', 'BUILD_TUPLE', 'RETURN_VALUE']
  try: o'rnida faqat NOP: True, istisnosiz yo'lda ishlovchi instruksiyalari yo'q: True
  co_exceptiontable: 24 bayt
  jadval yozuvlari: 6, birinchisi: L1 to L2 -> L3 [0]
  istisno bo'lsa ishlaydigan qism: ['PUSH_EXC_INFO', 'CHECK_EXC_MATCH', 'POP_EXCEPT', '→RERAISE', 'POP_EXCEPT', 'RERAISE', 'PUSH_EXC_INFO', 'RERAISE', 'POP_EXCEPT', 'RERAISE']

=== 5. with ===
  ['CALL', 'LOAD_SPECIAL(__exit__)', 'LOAD_SPECIAL(__enter__)', 'CALL', 'CALL', 'CALL', 'PUSH_EXC_INFO', 'WITH_EXCEPT_START']
  istisnolar jadvali ham bor: True

Nima ko'rsatdi: 2.5, 2.6-bo'limlar.

Misol 3 — dis bilan savollarga javob berish

python
"""+= atomar emas (qadamma-qadam simulyatsiya); in-literal konstantalari; global va lokal; almashtirish; metod chaqiruvi; comprehension inlining."""

import dis
import types


def nomlar(funksiya):
    natija = []
    for i in dis.get_instructions(funksiya):
        if i.opname in ("RESUME", "NOT_TAKEN", "CACHE"):
            continue
        arg = f"<kod {i.argval.co_name}>" if isinstance(i.argval, types.CodeType) else i.argrepr
        natija.append(f"{i.opname}({arg})" if arg else i.opname)
    return natija


class Hisob:
    def __init__(self):
        self.jami = 0

    def qosh(self, summa):
        self.jami += summa


print("=== 1. self.jami += summa ===")
print(f"  {nomlar(Hisob.qosh)}")


def ip_simulyatsiya(tartib):
    """Ikki 'ip': har biri O'QI → QO'SH → YOZ. Tartib — qaysi ip qaysi qadamni bajarishi."""
    hisob = {"jami": 100}
    lokal = {"A": {}, "B": {}}
    qadamlar = {"A": iter(["oqi", "qosh", "yoz"]), "B": iter(["oqi", "qosh", "yoz"])}
    for ip in tartib:
        qadam = next(qadamlar[ip])
        if qadam == "oqi":
            lokal[ip]["qiymat"] = hisob["jami"]
        elif qadam == "qosh":
            lokal[ip]["qiymat"] += 10
        else:
            hisob["jami"] = lokal[ip]["qiymat"]
    return hisob["jami"]


print(f"  ketma-ket  A A A B B B → {ip_simulyatsiya('AAABBB')} (kutilgan 120)")
print(f"  aralash    A B A B A B → {ip_simulyatsiya('ABABAB')} ⚠️ bitta qo'shish yo'qoldi")


def literallar(x):
    return x in [1, 2, 3], x in {1, 2, 3}, x in ("a", "b")


print("\n=== 2. in literal — har safar quriladimi ===")
print(f"  {[n for n in nomlar(literallar) if n.startswith(('LOAD_CONST', 'BUILD'))]}")


SOLIQ = 0.12


def global_bilan(summalar):
    return [s * SOLIQ for s in summalar]


def lokal_bilan(summalar, soliq=SOLIQ):
    return [s * soliq for s in summalar]


print("\n=== 3. Global va lokal ===")
print(f"  global: {[n for n in nomlar(global_bilan) if 'SOLIQ' in n or 'soliq' in n]}")
print(f"  lokal:  {[n for n in nomlar(lokal_bilan) if 'SOLIQ' in n or 'soliq' in n]}")


def almashtir(a, b):
    a, b = b, a
    return a


def metod(matn):
    return matn.upper()


print("\n=== 4. Almashtirish va metod chaqiruvi ===")
print(f"  a, b = b, a: {nomlar(almashtir)}")
print(f"  matn.upper(): {nomlar(metod)}")


def royxat_comp(nomlar_):
    return [n.title() for n in nomlar_]


def generator_ifoda(sonlar):
    return sum(x * x for x in sonlar)


print("\n=== 5. Comprehension va generator ifodasi ===")
rc = nomlar(royxat_comp)
gi = nomlar(generator_ifoda)
print(f"  list comprehension: alohida kod obyekti {any('<kod' in n for n in rc)}, LOAD_FAST_AND_CLEAR {any('AND_CLEAR' in n for n in rc)}")
print(f"  generator ifodasi:  alohida kod obyekti {any('<kod' in n for n in gi)}, MAKE_FUNCTION {'MAKE_FUNCTION' in gi}")
ichki = next(c for c in generator_ifoda.__code__.co_consts if isinstance(c, types.CodeType))
print(f"  generator kodi: nom {ichki.co_name!r}, bayroqlar {[n for b, n in dis.COMPILER_FLAG_NAMES.items() if ichki.co_flags & b]}")

print("\n=== 6. f-string ===")


def fstring(ism, ball):
    return f"{ism}: {ball:.1f} ball"


print(f"  {nomlar(fstring)}")

Natijaning muhim qismi:

text
=== 1. self.jami += summa ===
  ['LOAD_FAST_BORROW(self)', 'COPY', 'LOAD_ATTR(jami)', 'LOAD_FAST_BORROW(summa)', 'BINARY_OP(+=)', 'SWAP', 'STORE_ATTR(jami)', 'LOAD_CONST(None)', 'RETURN_VALUE']
  ketma-ket  A A A B B B → 120 (kutilgan 120)
  aralash    A B A B A B → 110 ⚠️ bitta qo'shish yo'qoldi

=== 2. in literal — har safar quriladimi ===
  ['LOAD_CONST((1, 2, 3))', 'LOAD_CONST(frozenset({1, 2, 3}))', "LOAD_CONST(('a', 'b'))", 'BUILD_TUPLE']

=== 3. Global va lokal ===
  global: ['LOAD_GLOBAL(SOLIQ)']
  lokal:  ['LOAD_FAST_BORROW(soliq)']

=== 4. Almashtirish va metod chaqiruvi ===
  a, b = b, a: ['LOAD_FAST_LOAD_FAST(b, a)', 'STORE_FAST_STORE_FAST(b, a)', 'LOAD_FAST_BORROW(a)', 'RETURN_VALUE']
  matn.upper(): ['LOAD_FAST_BORROW(matn)', 'LOAD_ATTR(upper + NULL|self)', 'CALL', 'RETURN_VALUE']

=== 5. Comprehension va generator ifodasi ===
  list comprehension: alohida kod obyekti False, LOAD_FAST_AND_CLEAR True
  generator ifodasi:  alohida kod obyekti True, MAKE_FUNCTION True
  generator kodi: nom '<genexpr>', bayroqlar ['OPTIMIZED', 'NEWLOCALS', 'NESTED', 'GENERATOR']

=== 6. f-string ===
  ['LOAD_FAST_BORROW(ism)', 'FORMAT_SIMPLE', "LOAD_CONST(': ')", 'LOAD_FAST_BORROW(ball)', "LOAD_CONST('.1f')", 'FORMAT_WITH_SPEC', "LOAD_CONST(' ball')", 'BUILD_STRING', 'RETURN_VALUE']

Nima ko'rsatdi: 2.3, 2.5, 2.7, 2.8-bo'limlar.

Misol 4 — Amaliy: bayt-kod asosidagi tekshiruvchi

Kod ko'rib chiqishni yengillashtirish uchun modul funksiyalarini bayt-kod bo'yicha tekshiradigan vosita yozamiz. U manbani emas, kompilyatsiya natijasini ko'radi — shuning uchun izohlar, qator uzilishlari va formatlash chalg'itmaydi. Qidiriladigan naqshlar:

  1. Xavfli chaqiruvlar: eval, exec, os.system, pickle.loads
  2. Sikl ichida takror yuklanadigan global nomlar (issiq sikl)
  3. is bilan literal taqqoslash (11.2-dars)
  4. except siz qolgan try … ya'ni hamma narsani yutadigan except Exception: pass
python
"""Manba satri → compile → barcha ichki kod obyektlari; instruksiyalar bo'yicha 4 xil tekshiruv; qator raqamlari bilan hisobot."""

import dis
import types
import warnings
from collections import Counter

MANBA = '''
import os, pickle

NARXLAR = {"olma": 12000, "nok": 15000}

def hisobot(buyurtmalar):
    jami = 0
    for b in buyurtmalar:
        jami += NARXLAR[b["mahsulot"]] * b["soni"]
        if len(NARXLAR) > 100:
            print("katta katalog")
    return jami

def sozlama_yukla(matn, fayl):
    if matn is "":
        return {}
    qiymat = eval(matn)
    os.system("cp " + fayl + " /tmp")
    return pickle.loads(qiymat)

class Xizmat:
    def ishga_tushir(self):
        try:
            self.ulan()
        except Exception:
            pass
        return [exec(x) for x in self.skriptlar]
'''

XAVFLI = {("eval",), ("exec",), ("os", "system"), ("pickle", "loads"), ("subprocess", "call")}


def kod_obyektlari(kod):
    yield kod
    for c in kod.co_consts:
        if isinstance(c, types.CodeType):
            yield from kod_obyektlari(c)


def tekshir(kod):
    topilmalar = []
    instr = [i for i in dis.get_instructions(kod) if i.opname != "CACHE"]

    for n, i in enumerate(instr):
        if i.opname in ("LOAD_GLOBAL", "LOAD_NAME") and (i.argval,) in XAVFLI:
            topilmalar.append((i.line_number, "xavfli chaqiruv", i.argval))
        if i.opname in ("LOAD_GLOBAL", "LOAD_NAME") and n + 1 < len(instr) and instr[n + 1].opname == "LOAD_ATTR":
            juft = (i.argval, instr[n + 1].argval)
            if juft in XAVFLI:
                topilmalar.append((i.line_number, "xavfli chaqiruv", ".".join(juft)))
        if i.opname == "IS_OP" and n > 0 and instr[n - 1].opname in ("LOAD_CONST", "LOAD_SMALL_INT") and instr[n - 1].argval is not None:
            topilmalar.append((i.line_number, "is bilan literal", repr(instr[n - 1].argval)))

    for n, i in enumerate(instr):
        if i.opname == "JUMP_BACKWARD":
            boshi = i.argval
            sikl = [x for x in instr if boshi <= x.offset <= i.offset]
            globallar = Counter(x.argval for x in sikl if x.opname == "LOAD_GLOBAL")
            for nom, soni in globallar.items():
                topilmalar.append((sikl[0].line_number, "siklda global", f"{nom} ×{soni}"))

    for n, i in enumerate(instr):
        if i.opname == "CHECK_EXC_MATCH" and n > 0 and instr[n - 1].argval in ("Exception", "BaseException"):
            keyingi = [x.opname for x in instr[n + 1:n + 6]]
            if "POP_EXCEPT" in keyingi and not any(op.startswith(("CALL", "LOAD_GLOBAL", "RAISE")) for op in keyingi):
                topilmalar.append((i.line_number, "yutilgan istisno", instr[n - 1].argval))
    return topilmalar


with warnings.catch_warnings():
    warnings.simplefilter("ignore", SyntaxWarning)       # 'matn is ""' kompilyatorning o'zi ogohlantiradi
    modul = compile(MANBA, "<xizmat.py>", "exec")
print("=== Hisobot ===")
jami = Counter()
for kod in kod_obyektlari(modul):
    for qator, tur, tafsilot in sorted(set(tekshir(kod))):
        jami[tur] += 1
        print(f"  {kod.co_qualname:22} qator {qator:>2}  {tur:18} {tafsilot}")
print(f"\n  jami: {dict(jami)}")
print(f"  tekshirilgan kod obyektlari: {[k.co_qualname for k in kod_obyektlari(modul)]}")

Natijaning muhim qismi:

text
=== Hisobot ===
  hisobot                qator  8  siklda global      NARXLAR ×2
  hisobot                qator  8  siklda global      len ×1
  hisobot                qator  8  siklda global      print ×1
  sozlama_yukla          qator 15  is bilan literal   ''
  sozlama_yukla          qator 17  xavfli chaqiruv    eval
  sozlama_yukla          qator 18  xavfli chaqiruv    os.system
  sozlama_yukla          qator 19  xavfli chaqiruv    pickle.loads
  Xizmat.ishga_tushir    qator 25  yutilgan istisno   Exception
  Xizmat.ishga_tushir    qator 27  siklda global      exec ×1
  Xizmat.ishga_tushir    qator 27  xavfli chaqiruv    exec

  jami: {'siklda global': 4, 'is bilan literal': 1, 'xavfli chaqiruv': 4, 'yutilgan istisno': 1}
  tekshirilgan kod obyektlari: ['<module>', 'hisobot', 'sozlama_yukla', 'Xizmat', 'Xizmat.ishga_tushir']

Nima ko'rsatdi: 2.3, 2.5–2.8-bo'limlar — bayt-kod darajasidagi tahlil formatlashga bog'liq emas va comprehension ichidagi exec ni ham topdi. Lekin u versiyaga bog'liq (instruksiya nomlari o'zgaradi) — ishlab chiqarishda AST asosidagi vositalar (ruff, bandit — 18-qism) barqarorroq.


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

Noto'g'ri fikr To'g'risi
"x += 1 — bitta amal" O'qish, amal, yozish — iplar orasida bo'linishi mumkin
"try bloki kodni sekinlashtiradi" 3.11+ da istisnosiz yo'lda NOP
"x in [1, 2, 3] har safar ro'yxat quradi" Kortej konstanta
"Comprehension — yashirin funksiya chaqiruvi" 3.12+ da inlining; generator ifodasi esa alohida kod
"a, b = b, a kortej yaratadi" Super-instruksiyalar, kortej yo'q
"Bayt-kod versiyalar orasida bir xil" Har versiyada o'zgaradi — barqaror API emas
"dis faqat CPython ichki ishlab chiquvchilari uchun" Unumdorlik, poyga holatlari va xulqni tushunishning amaliy vositasi
"LOAD_GLOBAL va LOAD_FAST farqi sezilmaydi" Issiq sikllarda sezilarli (3.11+ keshlari farqni kamaytirgan)

6. Keng tarqalgan xatolar va yechimlari

1. += ni iplarda atomar deb hisoblash

python
self.jami += summa                        # ❌ ko'p ipda qo'shishlar yo'qolishi mumkin
with self._qulf:
    self.jami += summa                    # ✅

2. Bayt-kodga tayangan kodni versiyalar bo'ylab ishlatish

python
if instr.opname == "LOAD_FAST": ...       # ❌ 3.14 da LOAD_FAST_BORROW ham bor
if instr.opname.startswith("LOAD_FAST"): ...   # ⚠️ yaxshiroq, lekin baribir versiyaga bog'liq

Tahlil vositalari uchun ast; dis — o'rganish va tashxis uchun.

3. dis.dis chiqishini matn sifatida tahlil qilish

python
if "BINARY_OP" in capture(dis.dis, f): ...   # ❌ mo'rt
any(i.opname == "BINARY_OP" for i in dis.get_instructions(f))   # ✅

4. Mikro-optimallashtirishni o'lchamasdan qilish

python
def f(royxat, _len=len): ...              # ⚠️ o'qilishi yomonlashadi, 3.11+ da foyda kichik

Avval profil (18-qism), keyin dis bilan sababni tushunish.

5. is bilan literal

python
if holat is "faol": ...                   # ❌ IS_OP + LOAD_CONST — SyntaxWarning
if holat == "faol": ...                   # ✅ COMPARE_OP

6. Istisnoni oddiy boshqaruv oqimi sifatida issiq siklda ishlatish

python
for k in kalitlar:
    try:
        jami += d[k]
    except KeyError:                      # ⚠️ kalitlarning ko'pi yo'q bo'lsa — har safar qimmat yo'l
        pass
jami = sum(d.get(k, 0) for k in kalitlar) # ✅ istisno kam bo'lmasa

7. dis ni modul darajasidagi kodga qo'llab, LOAD_NAME ni ko'rib hayron qolish

python
dis.dis(compile("x = 1\ny = x + 1", "<m>", "exec"))   # LOAD_NAME — modul darajasida lug'at

Funksiya ichida LOAD_FAST — shuning uchun skriptlarni main() funksiyasiga o'rash tezroq.

8. Generator ifodasini comprehension bilan bir xil deb hisoblash

python
sum([x * x for x in sonlar])              # inlining, lekin butun ro'yxat xotirada
sum(x * x for x in sonlar)                # alohida kod obyekti, xotira tejamkor

Tanlov — xotira va tezlik o'rtasida, o'lchab.


7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 9-qism (o'tilgan): EAFP va istisnolar narxi
  • 10.3-dars (o'tilgan): generatorlar — alohida kod obyekti
  • 10.12-dars (o'tilgan): closure — LOAD_DEREF
  • 11.7-dars (o'tilgan): konstantalarni birlashtirish va oldindan hisoblash
  • 12.1-dars (o'tilgan): kod obyekti
  • 12.3-dars: freymlar — instruksiyalar qayerda bajariladi
  • 12.5–12.6-darslar: GIL — iplar instruksiyalar orasida almashadi
  • 12.8-dars: ixtisoslashgan instruksiyalar (adaptive=True)
  • 14-qism: iplar, qulflar va poyga holatlari
  • 18-qism: profiling

8. Eng yaxshi amaliyotlar

  1. Xulq yoki unumdorlik haqida bahs — dis bilan tekshiring.

  2. get_instructions bilan dasturiy tahlil, dis.dis bilan ko'z bilan o'qish.

  3. Iplarda umumiy holatni o'zgartirish — har doim qulf bilan.

  4. Issiq kodni funksiyaga o'rang — LOAD_FAST modul darajasidagi LOAD_NAME dan tez.

  5. Istisnolarni haqiqatan kamdan-kam holatlar uchun ishlating.

  6. Bayt-kodga tayanadigan vositalarni versiyaga bog'lang yoki ast ni tanlang.

  7. Mikro-optimallashtirishdan oldin profil.

  8. dis.dis(f, adaptive=True) — kod "isitilgandan" keyin qanday ixtisoslashganini ko'rish uchun (12.8-dars).


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
import dis
def ops(f):
    return [i.opname for i in dis.get_instructions(f) if i.opname not in ("RESUME", "NOT_TAKEN")]
1.  def a(x):
        return x + 1
    print("BINARY_OP" in ops(a))
2.  def b(x):
        return x in [1, 2]
    print("BUILD_LIST" in ops(b))
3.  def c(x):
        return x is None
    print("IS_OP" in ops(c))
4.  def d(n):
        return [i for i in range(n)]
    print("MAKE_FUNCTION" in ops(d))
5.  def e(n):
        return list(i for i in range(n))
    print("MAKE_FUNCTION" in ops(e))
6.  def f():
        try:
            return 1
        except ValueError:
            return 2
    print(ops(f)[0])
7.  def g(s):
        return s.upper()
    print("LOAD_ATTR" in ops(g), "CALL" in ops(g))
8.  def h():
        return len
    print(ops(h))
9.  print(dis.opname[dis.opmap["RETURN_VALUE"]])
10. def k(a, b):
        a, b = b, a
    print("BUILD_TUPLE" in ops(k))
11. def m(x):
        return -x
    print([o for o in ops(m) if o.startswith("UNARY")])
12. def n(x, y):
        return x < y
    print(ops(n)[-2])
Javoblar
  1. True
  2. False — kortej konstanta
  3. True
  4. False — comprehension inlining
  5. True — generator ifodasi alohida kod obyekti
  6. NOP — try: uchun
  7. True True
  8. ['LOAD_GLOBAL', 'RETURN_VALUE']
  9. RETURN_VALUE
  10. False — super-instruksiyalar
  11. ['UNARY_NEGATIVE']
  12. COMPARE_OP

Vazifa 2: Xatolarni tuzating

python
1.  def binar_opmi(f):
        import io, contextlib
        buf = io.StringIO()
        with contextlib.redirect_stdout(buf):
            dis.dis(f)
        return "BINARY_OP" in buf.getvalue()

2.  def lokal_yuklashlar(f):
        return [i.argval for i in dis.get_instructions(f) if i.opname == "LOAD_FAST"]

3.  class Hisoblagich:
        def __init__(self):
            self.n = 0
        def oshir(self):
            self.n += 1          # 8 ta ip chaqiradi

4.  def satr_qatorlari(f):
        return {i.offset: i.starts_line for i in dis.get_instructions(f)}

5.  def jami(royxat):
        s = 0
        for x in royxat:
            try:
                s += int(x)
            except ValueError:
                pass
        return s                 # royxatning 90% i son emas
Javoblar
python
1.  def binar_opmi(f):
        return any(i.opname == "BINARY_OP" for i in dis.get_instructions(f))   # matn emas, obyektlar

2.  def lokal_yuklashlar(f):
        return [i.argval for i in dis.get_instructions(f)
                if i.opname.startswith(("LOAD_FAST", "STORE_FAST_LOAD_FAST"))]   # 3.14: BORROW va super-instruksiyalar
        # super-instruksiyada argval kortej bo'lishi mumkin — kerak bo'lsa ochib chiqing

3.  import threading
    class Hisoblagich:
        def __init__(self):
            self.n = 0
            self._qulf = threading.Lock()
        def oshir(self):
            with self._qulf:
                self.n += 1

4.  def satr_qatorlari(f):
        return {i.offset: i.line_number for i in dis.get_instructions(f)}      # starts_line — bool

5.  def jami(royxat):
        return sum(int(x) for x in royxat if isinstance(x, str) and x.lstrip("-").isdigit())
        # istisnolar ko'p bo'lsa — oldindan tekshirish arzonroq

Vazifa 3: Bayt-kod diff

bytecode_diff(f, g) funksiyasini yozing:

  1. Ikki funksiyaning instruksiyalarini difflib.SequenceMatcher bilan solishtirsin
  2. Farqlarni qo'shilgan/o'chirilgan/o'zgargan qilib rangli (ANSI) chiqarsin
  3. Uch juftlikda sinang: for va while, if/elif va match, list comprehension va map(lambda ...)
  4. Qaysi variant qisqaroq bayt-kod berishini va timeit bilan qaysi tezroq ekanini jadvalda ko'rsating — ular har doim mos keladimi?

Vazifa 4: Stek simulyatori

Kichik "VM" yozing:

  1. LOAD_CONST, LOAD_FAST, STORE_FAST, BINARY_OP (+, -, *, /), COMPARE_OP, POP_JUMP_IF_FALSE, JUMP_BACKWARD, RETURN_VALUE va LOAD_SMALL_INT ni qo'llab-quvvatlasin (super-instruksiyalarni ham ochib bajarsin)
  2. dis.get_instructions dan instruksiyalarni olib, stek va lokal o'zgaruvchilarni o'zi boshqarsin
  3. Har qadamda stek holatini chop etsin
  4. Faktorial va Fibonachchi funksiyalarini (siklli) bajarib, natijani haqiqiy chaqiruv bilan solishtirsin

Vazifa 5: Global nomlar auditi

Loyiha modullari uchun:

  1. Har funksiyada LOAD_GLOBAL bilan yuklanadigan nomlar ro'yxatini tuzing
  2. Builtins (len, print) va modul globallarini ajrating
  3. Funksiya ichida o'zgartiriladigan globallarni (STORE_GLOBAL) toping — ular refaktoring nomzodlari
  4. Natijani funksiya → nomlar grafi sifatida chiqaring

Vazifa 6: Istisno narxi

  1. try/except li va if li ikki funksiya yozing (lug'atdan kalit olish)
  2. Istisno 0%, 1%, 10%, 50%, 100% hollarda bo'lganda timeit bilan o'lchang
  3. Qaysi foizdan boshlab if tezroq bo'lishini toping
  4. dis bilan ikki yo'lning instruksiyalar sonini ko'rsatib, natijani tushuntiring

Vazifa 7: O'ylash

JVM bayt-kodi tipli instruksiyalarga ega (iadd, ladd, dadd), WebAssembly — tipli stek mashinasi, Lua 5 esa stek emas, registr mashinasi. CPython bayt-kodi tipsiz stek mashinasi. Bu dizayn tanlovlari interpretator tezligi, bayt-kod hajmi va kompilyator soddaligiga qanday ta'sir qiladi, va nega CPython 3.11+ "ixtisoslashgan instruksiyalar" orqali tipli instruksiyalarga yaqinlashmoqda?

Javob

Qisqa javob: tipli instruksiyalar interpretatorni tezlashtiradi (tur tekshiruvi kompilyatorda qilingan), registr mashinalari instruksiyalar sonini kamaytiradi; CPython esa dinamik tiplar tufayli kompilyatsiyada turni bila olmaydi va soddalikni tanlagan — tipsiz stek mashinasi. 3.11+ da u turni ish vaqtida kuzatib, instruksiyalarni joyida ixtisoslashtiradi — statik tipli bayt-kod afzalligini dinamik tarzda qo'lga kiritadi.

1. Stek va registr

Stek mashinasi (CPython, JVM, Wasm) Registr mashinasi (Lua 5, Dalvik)
a = b + c LOAD b; LOAD c; ADD; STORE a — 4 instruksiya ADD a, b, c — 1 instruksiya
Instruksiya hajmi Kichik Katta (bir nechta operand)
Kompilyator Oddiy — daraxtni aylanib chiqish Registr taqsimoti kerak
Dispatch soni Ko'p Kam — interpretatorda tezroq

Lua mualliflari registr mashinasiga o'tish interpretatorni sezilarli tezlashtirganini qayd etgan. CPython super-instruksiyalar (LOAD_FAST_LOAD_FAST) bilan dispatch sonini qisman kamaytiradi.

2. Tipli va tipsiz

Tipli (JVM, Wasm) Tipsiz (CPython)
x + y Kompilyator iadd yoki dadd ni tanlaydi BINARY_OP + — turni ish vaqtida aniqlaydi
Tekshiruv Yuklashda verifikator Har bajarilishda
Tezlik Instruksiya to'g'ridan-to'g'ri mashina amaliga yaqin Tur bo'yicha tarmoqlanish, __add__ qidiruvi
Moslashuvchanlik Tur tizimiga bog'liq Istalgan __add__

3. CPython 3.11+ ixtisoslashuvi

BINARY_OP +   →  (bir necha bajarilishdan keyin, int ko'rsa)  →  BINARY_OP_ADD_INT
LOAD_ATTR     →  LOAD_ATTR_INSTANCE_VALUE  (inline qiymatlar ofseti keshlanadi, 11.9-dars)
  • "Isitish" davrida tur kuzatiladi, keyin instruksiya joyida tezkor variantga almashtiriladi
  • Tur o'zgarsa — "deoptimizatsiya", umumiy variantga qaytish
  • Bu — JVM tipli instruksiyalari va V8 inline keshlari g'oyalarining dinamik tildagi sintezi (12.8-dars)
  • 3.13+ tajribaviy JIT shu ixtisoslashgan instruksiyalardan mashina kodi yasaydi

4. Nega CPython to'liq registr/tipli modelga o'tmaydi

  1. C API va ekotizim: bayt-kod ichki tafsilot bo'lsa-da, freym va stek tuzilishiga ko'p vosita (debugger, profiler, coverage) tayanadi
  2. Soddalik va xizmat ko'rsatish: CPython ko'ngilli ishlab chiquvchilar loyihasi — kompilyator soddaligi qadrlanadi
  3. Dinamizm: tur kompilyatsiyada noma'lum — tipli instruksiyalar faqat ish vaqtida mumkin, bu esa aynan ixtisoslashuv
  4. Bosqichma-bosqich yondashuv: super-instruksiyalar, ixtisoslashuv, JIT — har biri moslikni buzmasdan qo'shilmoqda

5. Xulosa

  1. Stek mashinasi — oddiy kompilyator, ko'proq instruksiya; registr mashinasi — kamroq dispatch, murakkabroq kompilyator
  2. Tipli bayt-kod interpretatorni tezlashtiradi, lekin statik turlarni talab qiladi
  3. CPython tipsiz stek mashinasi va turni ish vaqtida kuzatib ixtisoslashtirish yo'lini tanlagan
  4. Super-instruksiyalar va ixtisoslashuv — registr va tipli modellar afzalliklarini moslikni saqlagan holda olish usuli

Nimani mustahkamlaydi: 2.1–2.8-bo'limlar.


Xulosa

Bu darsda CPython bayt-kodini o'qishni o'rgandik.

Eng muhim uch fikr:

  1. dis — "Python aslida nima qilyapti" ga javob. dis.dis ko'z bilan o'qish uchun, dis.get_instructions dasturiy tahlil uchun: har Instruction da nom, argument, offset, qator va ustunlar bor. Chiqish — manba qatori, yorliq, instruksiya va uning ma'nosi; bayt-kod versiyalar orasida o'zgaradi, tamoyillar esa saqlanadi.

  2. Instruksiya oilalari va naqshlar. Lokal nomlar LOAD_FAST, globallar LOAD_GLOBAL, atributlar LOAD_ATTR bilan yuklanadi; amallar BINARY_OP, taqqoslash COMPARE_OP/IS_OP/CONTAINS_OP, shartlar POP_JUMP_IF_*, sikllar FOR_ITER/JUMP_BACKWARD. x += 1 — uch qadam va iplarda atomar emas; x in [1, 2, 3] — kortej konstanta; a, b = b, a — kortejsiz super-instruksiyalar.

  3. Istisnolar jadvali va inlining. 3.11+ da try istisnosiz yo'lda NOP — istisno bo'lganda interpretator co_exceptiontable dan ishlovchini topadi; shuning uchun istisnolar faqat kamdan-kam holatlar uchun. 3.12+ da list/set/dict comprehensionlar funksiyaga joylashtiriladi, generator ifodalari esa alohida kod obyekti bo'lib qoladi.

Keyingi darsda bu instruksiyalar qayerda bajarilishini ko'ramiz: freym obyekti, lokal o'zgaruvchilar va qiymatlar steki, chaqiruv steki, sys._getframe, traceback qanday quriladi va rekursiya chegarasi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
12.2-dars: dis moduli bilan bytecode o'qish — IlmHamroh