Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. dis API
- 2.2. Chiqishni o'qish
- 2.3. Instruksiya oilalari
- 2.4. Stek effekti
- 2.5. Shartlar va sikllar
- 2.6. Istisnolar jadvali
- 2.7. Comprehension va generator ifodalari
- 2.8. dis bilan savollarga javob
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — O'z dis jadvalimiz: stek chuqurligi bilan
- Misol 2 — Boshqaruv oqimi va istisnolar
- Misol 3 — dis bilan savollarga javob berish
- Misol 4 — Amaliy: bayt-kod asosidagi tekshiruvchi
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
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. yozishUch 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,Instructionmaydonlari - Chiqishni o'qish: qator, yorliq, instruksiya, argument
- Asosiy instruksiya oilalari: yuklash/saqlash, amallar, taqqoslash, sakrashlar, chaqiruvlar
- Stek effekti va
co_stacksize - Shartlar, sikllar,
and/orbayt-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
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 ↔ raqamInstruction 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 qatoriBayt-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 qaytariladiGenerator 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_exceptiontableOilalar
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 + ExceptionTableNaqshlar
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 jadvali4. Batafsil misollar
Misol 1 — O'z dis jadvalimiz: stek chuqurligi bilan
"""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:
=== 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
"""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:
=== 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: TrueNima ko'rsatdi: 2.5, 2.6-bo'limlar.
Misol 3 — dis bilan savollarga javob berish
"""+= 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:
=== 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:
- Xavfli chaqiruvlar:
eval,exec,os.system,pickle.loads - Sikl ichida takror yuklanadigan global nomlar (issiq sikl)
isbilan literal taqqoslash (11.2-dars)exceptsiz qolgantry… ya'ni hamma narsani yutadiganexcept Exception: pass
"""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:
=== 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
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
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
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
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
if holat is "faol": ... # ❌ IS_OP + LOAD_CONST — SyntaxWarning
if holat == "faol": ... # ✅ COMPARE_OP6. Istisnoni oddiy boshqaruv oqimi sifatida issiq siklda ishlatish
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'lmasa7. dis ni modul darajasidagi kodga qo'llab, LOAD_NAME ni ko'rib hayron qolish
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
sum([x * x for x in sonlar]) # inlining, lekin butun ro'yxat xotirada
sum(x * x for x in sonlar) # alohida kod obyekti, xotira tejamkorTanlov — 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
Xulq yoki unumdorlik haqida bahs —
disbilan tekshiring.get_instructionsbilan dasturiy tahlil,dis.disbilan ko'z bilan o'qish.Iplarda umumiy holatni o'zgartirish — har doim qulf bilan.
Issiq kodni funksiyaga o'rang —
LOAD_FASTmodul darajasidagiLOAD_NAMEdan tez.Istisnolarni haqiqatan kamdan-kam holatlar uchun ishlating.
Bayt-kodga tayanadigan vositalarni versiyaga bog'lang yoki
astni tanlang.Mikro-optimallashtirishdan oldin profil.
dis.dis(f, adaptive=True)— kod "isitilgandan" keyin qanday ixtisoslashganini ko'rish uchun (12.8-dars).
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
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
TrueFalse— kortej konstantaTrueFalse— comprehension inliningTrue— generator ifodasi alohida kod obyektiNOP—try:uchunTrue True['LOAD_GLOBAL', 'RETURN_VALUE']RETURN_VALUEFalse— super-instruksiyalar['UNARY_NEGATIVE']COMPARE_OP
Vazifa 2: Xatolarni tuzating
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 emasJavoblar
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 arzonroqVazifa 3: Bayt-kod diff
bytecode_diff(f, g) funksiyasini yozing:
- Ikki funksiyaning instruksiyalarini
difflib.SequenceMatcherbilan solishtirsin - Farqlarni qo'shilgan/o'chirilgan/o'zgargan qilib rangli (ANSI) chiqarsin
- Uch juftlikda sinang:
forvawhile,if/elifvamatch, list comprehension vamap(lambda ...) - Qaysi variant qisqaroq bayt-kod berishini va
timeitbilan qaysi tezroq ekanini jadvalda ko'rsating — ular har doim mos keladimi?
Vazifa 4: Stek simulyatori
Kichik "VM" yozing:
LOAD_CONST,LOAD_FAST,STORE_FAST,BINARY_OP(+, -, *, /),COMPARE_OP,POP_JUMP_IF_FALSE,JUMP_BACKWARD,RETURN_VALUEvaLOAD_SMALL_INTni qo'llab-quvvatlasin (super-instruksiyalarni ham ochib bajarsin)dis.get_instructionsdan instruksiyalarni olib, stek va lokal o'zgaruvchilarni o'zi boshqarsin- Har qadamda stek holatini chop etsin
- Faktorial va Fibonachchi funksiyalarini (siklli) bajarib, natijani haqiqiy chaqiruv bilan solishtirsin
Vazifa 5: Global nomlar auditi
Loyiha modullari uchun:
- Har funksiyada
LOAD_GLOBALbilan yuklanadigan nomlar ro'yxatini tuzing - Builtins (
len,print) va modul globallarini ajrating - Funksiya ichida o'zgartiriladigan globallarni (
STORE_GLOBAL) toping — ular refaktoring nomzodlari - Natijani funksiya → nomlar grafi sifatida chiqaring
Vazifa 6: Istisno narxi
try/exceptli vaifli ikki funksiya yozing (lug'atdan kalit olish)- Istisno 0%, 1%, 10%, 50%, 100% hollarda bo'lganda
timeitbilan o'lchang - Qaysi foizdan boshlab
iftezroq bo'lishini toping disbilan 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
- C API va ekotizim: bayt-kod ichki tafsilot bo'lsa-da, freym va stek tuzilishiga ko'p vosita (debugger, profiler, coverage) tayanadi
- Soddalik va xizmat ko'rsatish: CPython ko'ngilli ishlab chiquvchilar loyihasi — kompilyator soddaligi qadrlanadi
- Dinamizm: tur kompilyatsiyada noma'lum — tipli instruksiyalar faqat ish vaqtida mumkin, bu esa aynan ixtisoslashuv
- Bosqichma-bosqich yondashuv: super-instruksiyalar, ixtisoslashuv, JIT — har biri moslikni buzmasdan qo'shilmoqda
5. Xulosa
- Stek mashinasi — oddiy kompilyator, ko'proq instruksiya; registr mashinasi — kamroq dispatch, murakkabroq kompilyator
- Tipli bayt-kod interpretatorni tezlashtiradi, lekin statik turlarni talab qiladi
- CPython tipsiz stek mashinasi va turni ish vaqtida kuzatib ixtisoslashtirish yo'lini tanlagan
- 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:
dis— "Python aslida nima qilyapti" ga javob.dis.disko'z bilan o'qish uchun,dis.get_instructionsdasturiy tahlil uchun: harInstructionda 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.Instruksiya oilalari va naqshlar. Lokal nomlar
LOAD_FAST, globallarLOAD_GLOBAL, atributlarLOAD_ATTRbilan yuklanadi; amallarBINARY_OP, taqqoslashCOMPARE_OP/IS_OP/CONTAINS_OP, shartlarPOP_JUMP_IF_*, sikllarFOR_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.Istisnolar jadvali va inlining. 3.11+ da
tryistisnosiz yo'ldaNOP— istisno bo'lganda interpretatorco_exceptiontabledan 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.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!