IlmHamroh
Python kursi/CPython ichki tuzilishi7/8-dars22 daqiqa
Mundarija (21)

12.7-dars: Alternativ interpretatorlar: PyPy, MicroPython

12-QISM — CPYTHON ICHKI TUZILISHI · 7-dars


1. Kirish va motivatsiya

Shu paytgacha "Python" deganda CPython ni nazarda tutdik: havolalar sanog'i, GIL, bayt-kod, PyObject. Lekin Python — bu til spetsifikatsiyasi, CPython esa uning eng mashhur implementatsiyasi. Boshqalari ham bor va ular boshqacha qarorlar qabul qilgan.

Real vaziyat. Narxlarni hisoblaydigan xizmat sof Python sikllarda kuniga 40 daqiqa ishlardi. Jamoa kodni o'zgartirmasdan PyPy da ishga tushirdi — 6 daqiqa. Lekin ikkinchi xizmat (NumPy va psycopg ga tayangan) PyPy da sekinlashdi va bir nechta kutubxona umuman ishlamadi.

Uchinchi vaziyat: IoT qurilmasi uchun sensor kodi yozildi. Mikrokontrollerda 264 KB operativ xotira bor — CPython u yerga sig'maydi. MicroPython esa sig'adi, lekin pandas u yerda yo'q va float 32 bitli.

Shuning uchun "Python kodim qayerda ishlaydi?" degan savol jiddiy: u yozgan kodingiz qaysi farazlarga tayanishiga bog'liq.

Bu darsda:

  • Til va implementatsiya farqi; spetsifikatsiya nimani kafolatlaydi
  • Asosiy implementatsiyalar: CPython, PyPy, MicroPython, GraalPy, Pyodide va boshqalar
  • PyPy JIT qanday ishlaydi: isitish, iz (trace), deoptimizatsiya
  • CPython'ga xos farazlar: __del__ vaqti, id(), interning, GIL atomarligi
  • Implementatsiyani va imkoniyatlarni aniqlash
  • MicroPython cheklovlari: xotira, float, standart kutubxona
  • Amaliy: kodning ko'chuvchanligini tekshiruvchi

2. Nazariya — chuqur tushuntirish

2.1. Til va implementatsiya

Nima
Til spetsifikatsiyasi Sintaksis, semantika, standart kutubxona hujjatlari — "Language Reference"
Implementatsiya Shu qoidalarni bajaradigan dastur: CPython, PyPy, MicroPython, ...
Implementatsiya tafsiloti Hujjatlarda "CPython implementation detail" deb belgilangan xulq

Spetsifikatsiya kafolatlaydi: dict kiritish tartibini saqlaydi (3.7+), int cheksiz, // yaxlitlash, istisnolar semantikasi, with protokoli.

Spetsifikatsiya kafolatlamaydi: obyekt qachon o'chishi, id() ning ma'nosi, satrlar interningi, list.append ning atomarligi, sys.getsizeof natijasi.

2.2. Asosiy implementatsiyalar

Implementatsiya Asosi Kuchli tomoni Cheklovi
CPython C Etalon, butun ekotizim, C API Sof Python tezligi past, GIL
PyPy RPython + izli (tracing) JIT Uzoq ishlaydigan sof Python kodda 5–20 barobar tez C kengaytmalar sekin (cpyext), xotira ko'proq, isitish kerak
MicroPython C, mikrokontrollerlar uchun Bir necha yuz KB xotirada ishlaydi Kutubxonalarning kichik qismi, cheklangan turlar
CircuitPython MicroPython forki Ta'lim va elektronika uchun qulay Xuddi shunday cheklovlar
GraalPy GraalVM (Java) Java ekotizimi bilan integratsiya, JIT Yosh, ba'zi kutubxonalar ishlamaydi
Pyodide CPython → WebAssembly Brauzerda ishlaydi, NumPy/pandas bor Sekinroq, tarmoq va fayl cheklovlari
RustPython Rust O'rganish, WASM tajribalari To'liq emas
IronPython .NET .NET integratsiyasi Ekotizim cheklangan

Kompilyatorlar (interpretator emas, lekin shu qatorda eslanadi): Cython (Python → C), Nuitka (Python → C++ binar), mypyc — ular CPython ustida ishlaydi va mos kod talab qiladi (19, 30-qismlar).

2.3. PyPy va JIT

Izli (tracing) JIT: interpretator tez-tez bajariladigan sikl izlarini kuzatadi, ularni mashina kodiga kompilyatsiya qiladi va turlar haqidagi farazlarni "qo'riqchi" (guard) tekshiruvlari bilan himoyalaydi. Faraz buzilsa — deoptimizatsiya, interpretatorga qaytish.

Xususiyat Oqibat
Isitish (warm-up) Dastlabki soniyalar sekin; qisqa skriptlarda PyPy foyda bermaydi
Sof Python sikllar Eng katta yutuq shu yerda
C kengaytmalar cpyext qatlami orqali — ko'pincha sekinroq (NumPy ishlaydi, lekin CPython'dagidek emas)
Xotira Odatda ko'proq (JIT kodi, obyekt modeli boshqacha)
Havolalar sanog'i yo'q Obyektlar kechikib o'chadi — __del__ va fayl yopilishi kafolatlanmaydi
GIL PyPy'da ham bor

Qoida: PyPy — uzoq ishlaydigan, sof Python hisob-kitobga boy xizmatlar uchun; C kutubxonalarga tayangan kod uchun emas.

2.4. CPython'ga xos farazlar

Faraz CPython Boshqa joyda
Oxirgi havola ketishi bilan obyekt o'chadi (refcount) PyPy, GraalPy — GC qachondir
open(...).read() fayl darhol yopiladi Fayl deskriptori uzoq ochiq qoladi
id(obj) — xotira manzili Boshqa raqam
Kod konstantalari interned, is ishlaydi Boshqacha
list.append atomar (GIL) Erkin ipli yig'ma, boshqa implementatsiyalar
sys.getrefcount, sys._getframe Yo'q yoki boshqacha
ctypes.pythonapi, C kengaytmalar Yo'q yoki sekin
sys.getsizeof MicroPython'da yo'q

Ko'chuvchan yozish:

python
with open(yol) as f:        # ✅ aniq yopish — hamma joyda ishlaydi
    matn = f.read()

matn = open(yol).read()     # ❌ CPython'da ishlaydi, PyPy'da deskriptor qoladi

2.5. Implementatsiyani aniqlash

python
sys.implementation.name          # 'cpython', 'pypy', 'micropython', 'graalpy'
sys.implementation.version       # implementatsiya versiyasi
platform.python_implementation() # 'CPython', 'PyPy', ...
sys.version_info                 # til versiyasi (hammasida bor)

Imkoniyatni tekshiring, nomni emas:

python
if sys.implementation.name == "cpython":     # ❌ mo'rt
    ...
if hasattr(sys, "getrefcount"):              # ✅ imkoniyat bo'yicha
    ...
try:
    import ujson as json                     # ✅ muqobil bilan
except ImportError:
    import json

2.6. MicroPython cheklovlari

Jihat MicroPython
Xotira Bir necha o'n KB dan boshlab
Standart kutubxona Kichik qismi: sys, time, json, os (qisqartirilgan), machine, network
Turlar int cheksiz (ko'p portlarda), float odatda 32 bitli, complex bo'lmasligi mumkin
Yo'q narsalar sys.getsizeof (ba'zi portlarda), inspect, typing (faqat stub), ko'p dunder tafsilotlar
Qo'shimcha machine, network, bluetooth — apparatga kirish
Bayt-kod O'z formati, .mpy fayllari

Kod yozish uslubi: kam xotira ajratish, bytearray ni qayta ishlatish, generatorlar, global obyektlarni oldindan yaratish.

2.7. Qachon qaysi biri

Vazifa Tanlov
Umumiy backend, ma'lumot tahlili, ML CPython (ekotizim)
Uzoq ishlaydigan sof Python hisob PyPy (o'lchab)
Mikrokontroller, sensor MicroPython / CircuitPython
Brauzerda Python Pyodide
Java infratuzilmasi bilan integratsiya GraalPy
Bitta faylli binar Nuitka, PyInstaller (19-qism)
Issiq kodni tezlashtirish Cython, C/Rust kengaytma (30-qism)

3. Tez ma'lumotnoma

Aniqlash

sys.implementation.name / .version      platform.python_implementation()
hasattr(sys, "getrefcount")             try: import X except ImportError: ...

Ko'chuvchanlik qoidalari

with / finalize  →  refcount ga tayanmang
==               →  is (qiymatlar uchun) o'rniga
qulflar          →  GIL atomarligiga tayanmang
id()             →  faqat identifikator, manzil emas
sys.getsizeof, ctypes, gc tafsilotlari → CPython'ga xos

Implementatsiyalar

CPython (etalon) · PyPy (JIT, sof Python) · MicroPython (mikrokontroller)
GraalPy (JVM) · Pyodide (brauzer) · Cython/Nuitka (kompilyatorlar)

4. Batafsil misollar

Misol 1 — Implementatsiya va imkoniyatlarni aniqlash

python
"""sys.implementation va platform; imkoniyatlarni tekshirish; nom bo'yicha emas, imkoniyat bo'yicha tarmoqlanish."""

import platform
import sys


def bor(nom, tekshiruv):
    try:
        return "✅" if tekshiruv() else "❌"
    except Exception:
        return "❌"


print("=== 1. Implementatsiya ===")
print(f"  sys.implementation.name: {sys.implementation.name}")
print(f"  platform.python_implementation(): {platform.python_implementation()}")
print(f"  til versiyasi: {'.'.join(map(str, sys.version_info[:3]))}")
print(f"  implementatsiya versiyasi ham bor: {hasattr(sys.implementation, 'version')}")
print(f"  cache_tag: {sys.implementation.cache_tag}")

print("\n=== 2. Imkoniyatlar (boshqa implementatsiyalarda farq qiladi) ===")
IMKONIYATLAR = {
    "sys.getrefcount": lambda: sys.getrefcount(object()) > 0,
    "sys._getframe": lambda: sys._getframe() is not None,
    "sys.getsizeof": lambda: sys.getsizeof(1) > 0,
    "sys._is_gil_enabled": lambda: sys._is_gil_enabled() in (True, False),
    "ctypes": lambda: __import__("ctypes").sizeof(__import__("ctypes").c_void_p) > 0,
    "gc.get_referrers": lambda: isinstance(__import__("gc").get_referrers(object()), list),
    "threading": lambda: __import__("threading").active_count() >= 1,
    "dataclasses": lambda: __import__("dataclasses").is_dataclass(object) is False,
    "decimal (C tezkor)": lambda: __import__("decimal").__file__ is not None,
}
for nom, tekshiruv in IMKONIYATLAR.items():
    print(f"  {nom:22} {bor(nom, tekshiruv)}")

print("\n=== 3. Nom bo'yicha emas, imkoniyat bo'yicha ===")


def tirikmi(obj_havola):
    """Obyekt tirikligini har joyda ishlaydigan usulda tekshirish."""
    return obj_havola() is not None


def xotira_hisoboti(obj):
    if hasattr(sys, "getsizeof"):
        return f"{sys.getsizeof(obj)} bayt"
    return "o'lchov mavjud emas (masalan, MicroPython)"


import weakref


class Yozuv:
    pass


y = Yozuv()
havola = weakref.ref(y)
print(f"  weakref bilan tirikligi: {tirikmi(havola)}")
del y
print(f"  o'chirilgandan keyin: {tirikmi(havola)}  ← CPython'da darhol, boshqa joyda GC dan keyin")
print(f"  xotira hisoboti: {xotira_hisoboti([1, 2, 3])}")
print(f"  JSON kutubxonasi: {'ujson' if 'ujson' in sys.modules else 'json'} (MicroPython'da ujson bo'lishi mumkin)")

Natijaning muhim qismi:

text
=== 1. Implementatsiya ===
  sys.implementation.name: cpython
  platform.python_implementation(): CPython
  til versiyasi: 3.14.5
  implementatsiya versiyasi ham bor: True
  cache_tag: cpython-314

=== 2. Imkoniyatlar (boshqa implementatsiyalarda farq qiladi) ===
  sys.getrefcount        ✅
  sys._getframe          ✅
  sys.getsizeof          ✅
  sys._is_gil_enabled    ✅
  ctypes                 ✅
  gc.get_referrers       ✅
  threading              ✅
  dataclasses            ✅
  decimal (C tezkor)     ✅

=== 3. Nom bo'yicha emas, imkoniyat bo'yicha ===
  weakref bilan tirikligi: True
  o'chirilgandan keyin: False  ← CPython'da darhol, boshqa joyda GC dan keyin
  xotira hisoboti: 88 bayt
  JSON kutubxonasi: json (MicroPython'da ujson bo'lishi mumkin)

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

Misol 2 — CPython'ga xos farazlar va ularning ko'chuvchan muqobillari

python
"""__del__ vaqti: refcount va GC; sikl orqali 'PyPy kabi' kechikishni ko'rsatish; id(), interning, GIL atomarligi; to'g'ri yozish usullari."""

import gc
import sys
import weakref


jurnal = []


class Fayl:
    """Resursni __del__ da yopadigan (yomon) sinf."""

    def __init__(self, nom):
        self.nom = nom
        jurnal.append(f"ochildi:{nom}")

    def __del__(self):
        jurnal.append(f"yopildi:{self.nom}")


print("=== 1. __del__ qachon ishlaydi ===")
f = Fayl("hisobot.csv")
del f
print(f"  refcount nolga tushdi → darhol: {jurnal}")

jurnal.clear()
a, b = Fayl("a.log"), Fayl("b.log")
a.juft, b.juft = b, a          # sikl: refcount yetarli emas
del a, b
print(f"  sikl ichida, gc.collect() dan oldin: {[x for x in jurnal if x.startswith('yopildi')]}")
gc.collect()
print(f"  gc.collect() dan keyin: {[x for x in jurnal if x.startswith('yopildi')]}")
print("  ⭐ PyPy va GraalPy'da refcount yo'q — oddiy holat ham shunday 'kechikadi'")

print("\n=== 2. Ko'chuvchan yechim ===")
jurnal.clear()


class Xavfsiz:
    def __init__(self, nom):
        self.nom = nom
        jurnal.append(f"ochildi:{nom}")

    def yop(self):
        if self.nom:
            jurnal.append(f"yopildi:{self.nom}")
            self.nom = None

    def __enter__(self):
        return self

    def __exit__(self, *xato):
        self.yop()
        return False


with Xavfsiz("tranzaksiya.db") as x:
    pass
print(f"  with bloki: {jurnal}  ← implementatsiyadan qat'i nazar aniq vaqtda")
jurnal.clear()
x = Xavfsiz("kesh.bin")
weakref.finalize(x, jurnal.append, "yopildi:kesh.bin (finalize)")
del x
print(f"  weakref.finalize zaxira sifatida: {jurnal}")

print("\n=== 3. Boshqa farazlar ===")
s1 = "".join(["so", "liq"])
s2 = "soliq"
print(f"  id() — CPython'da manzil: {id(s2) > 0}, lekin ma'nosi implementatsiyaga bog'liq")
print(f"  ish vaqtidagi satr konstanta bilan bitta obyektmi: {s1 is s2} (11.7-dars), teng: {s1 == s2}")
print(f"  {'✅ == ishlatildi' if s1 == s2 else ''} — 'is' ni qiymat uchun ishlatmang")
kichik = 256
print(f"  kichik sonlar keshi CPython tafsiloti: {kichik is int('256')}")
print(f"  sys.getrefcount mavjud: {hasattr(sys, 'getrefcount')} — PyPy'da yo'q, kod unga tayanmasin")
print("  list.append atomarligi GIL ga bog'liq 12.5-bob — qulf ishlating")

Natijaning muhim qismi:

text
=== 1. __del__ qachon ishlaydi ===
  refcount nolga tushdi → darhol: ['ochildi:hisobot.csv', 'yopildi:hisobot.csv']
  sikl ichida, gc.collect() dan oldin: []
  gc.collect() dan keyin: ['yopildi:a.log', 'yopildi:b.log']
  ⭐ PyPy va GraalPy'da refcount yo'q — oddiy holat ham shunday 'kechikadi'

=== 2. Ko'chuvchan yechim ===
  with bloki: ['ochildi:tranzaksiya.db', 'yopildi:tranzaksiya.db']  ← implementatsiyadan qat'i nazar aniq vaqtda
  weakref.finalize zaxira sifatida: ['ochildi:kesh.bin', 'yopildi:kesh.bin (finalize)']

=== 3. Boshqa farazlar ===
  id() — CPython'da manzil: True, lekin ma'nosi implementatsiyaga bog'liq
  ish vaqtidagi satr konstanta bilan bitta obyektmi: False (11.7-dars), teng: True
  ✅ == ishlatildi — 'is' ni qiymat uchun ishlatmang
  kichik sonlar keshi CPython tafsiloti: True
  sys.getrefcount mavjud: True — PyPy'da yo'q, kod unga tayanmasin
  list.append atomarligi GIL ga bog'liq 12.5-bob — qulf ishlating

Nima ko'rsatdi: 2.4-bo'lim — siklli obyektlar CPython'da ham "kechikib" o'chadi; bu PyPy semantikasining kichik namunasi.

Misol 3 — Ko'chuvchanlik tekshiruvchisi

python
"""AST bilan manbani tekshirish: CPython'ga xos API lar, xavfli naqshlar va MicroPython'da yo'q modullar."""

import ast

CPYTHON_API = {
    "sys.getrefcount": "havolalar sanog'i — faqat CPython",
    "sys._getframe": "freymlar — PyPy'da cheklangan",
    "sys.getsizeof": "MicroPython'da yo'q",
    "ctypes.pythonapi": "C API — faqat CPython",
    "gc.get_referrers": "GC tafsiloti — implementatsiyaga bog'liq",
    "gc.get_objects": "GC tafsiloti",
}

MICROPYTHON_YOQ = {"pandas", "numpy", "inspect", "dataclasses", "typing", "sqlite3", "multiprocessing", "concurrent"}


class Tekshiruvchi(ast.NodeVisitor):
    def __init__(self):
        self.topilmalar = []

    def qayd(self, tugun, tur, matn):
        self.topilmalar.append((tugun.lineno, tur, matn))

    def visit_Attribute(self, tugun):
        nom = ast.unparse(tugun)
        if nom in CPYTHON_API:
            self.qayd(tugun, "CPython API", f"{nom} — {CPYTHON_API[nom]}")
        self.generic_visit(tugun)

    def visit_Import(self, tugun):
        for a in tugun.names:
            if a.name.split(".")[0] in MICROPYTHON_YOQ:
                self.qayd(tugun, "MicroPython'da yo'q", a.name)
        self.generic_visit(tugun)

    def visit_ImportFrom(self, tugun):
        if tugun.module and tugun.module.split(".")[0] in MICROPYTHON_YOQ:
            self.qayd(tugun, "MicroPython'da yo'q", tugun.module)
        self.generic_visit(tugun)

    def visit_Compare(self, tugun):
        for op, tomon in zip(tugun.ops, tugun.comparators):
            if isinstance(op, (ast.Is, ast.IsNot)) and isinstance(tomon, ast.Constant) and tomon.value is not None:
                self.qayd(tugun, "is bilan qiymat", f"{ast.unparse(tugun)} — == ishlating 11.2-bob")
        self.generic_visit(tugun)

    def visit_FunctionDef(self, tugun):
        if tugun.name == "__del__":
            self.qayd(tugun, "__del__ ga tayanish", "resursni with yoki weakref.finalize bilan yoping")
        self.generic_visit(tugun)

    def visit_Call(self, tugun):
        # open(...).read() — fayl aniq yopilmaydi
        if isinstance(tugun.func, ast.Attribute) and isinstance(tugun.func.value, ast.Call):
            ichki = tugun.func.value.func
            if isinstance(ichki, ast.Name) and ichki.id == "open" and tugun.func.attr in {"read", "readlines", "write"}:
                self.qayd(tugun, "yopilmagan fayl", f"{ast.unparse(tugun)[:40]} — with ishlating")
        self.generic_visit(tugun)


MANBA = '''
import sys, gc, ctypes
import pandas as pd
from dataclasses import dataclass

def kesh_hajmi(kesh):
    return sys.getsizeof(kesh)

def nusxalar(obj):
    return sys.getrefcount(obj) - 1

class Ulanish:
    def __del__(self):
        self.soket.close()

def sozlama_oqi(yol):
    matn = open(yol).read()
    if matn is "":
        return {}
    return matn

def freym():
    return sys._getframe(1).f_code.co_name
'''

daraxt = ast.parse(MANBA)
tekshiruvchi = Tekshiruvchi()
tekshiruvchi.visit(daraxt)

print("=== Ko'chuvchanlik hisoboti ===")
for qator, tur, matn in sorted(tekshiruvchi.topilmalar):
    print(f"  qator {qator:>2}  {tur:22} {matn}")
print(f"\n  jami: {len(tekshiruvchi.topilmalar)} ta ogohlantirish")
turlar = {}
for _, tur, _ in tekshiruvchi.topilmalar:
    turlar[tur] = turlar.get(tur, 0) + 1
print(f"  turlar bo'yicha: {dict(sorted(turlar.items()))}")

Natijaning muhim qismi:

text
=== Ko'chuvchanlik hisoboti ===
  qator  3  MicroPython'da yo'q    pandas
  qator  4  MicroPython'da yo'q    dataclasses
  qator  7  CPython API            sys.getsizeof — MicroPython'da yo'q
  qator 10  CPython API            sys.getrefcount — havolalar sanog'i — faqat CPython
  qator 13  __del__ ga tayanish    resursni with yoki weakref.finalize bilan yoping
  qator 17  yopilmagan fayl        open(yol).read() — with ishlating
  qator 18  is bilan qiymat        matn is '' — == ishlating 11.2-bob
  qator 23  CPython API            sys._getframe — freymlar — PyPy'da cheklangan

  jami: 8 ta ogohlantirish
  turlar bo'yicha: {'CPython API': 3, "MicroPython'da yo'q": 2, '__del__ ga tayanish': 1, 'is bilan qiymat': 1, 'yopilmagan fayl': 1}

Nima ko'rsatdi: 2.4-bo'lim — is bilan taqqoslash va __del__ ga tayanish CPython'da "ishlaydi", boshqa joyda esa yo'q.

Misol 4 — Amaliy: bir kod, to'rt muhit

Sensor ma'lumotlarini yig'adigan modul uchta joyda ishlashi kerak: server (CPython), mikrokontroller (MicroPython) va brauzer (Pyodide). Yechim — imkoniyatlarni aniqlash va muqobillar bilan moslashuvchan qatlam.

python
"""Muhit qatlamini imkoniyatlar bo'yicha qurish; MicroPython uslubidagi cheklangan muhitni taqlid qilib sinash."""

import sys


def muhit_yasa(mavjud_modullar=None, imkoniyatlar=None):
    """mavjud_modullar=None — haqiqiy muhit; aks holda taqlid (simulyatsiya)."""
    haqiqiy = mavjud_modullar is None
    bor = (lambda nom: nom in sys.modules or _import_mumkinmi(nom)) if haqiqiy else (lambda nom: nom in mavjud_modullar)
    imkon = (lambda nom: hasattr(sys, nom)) if haqiqiy else (lambda nom: nom in (imkoniyatlar or set()))
    return {
        "nom": sys.implementation.name if haqiqiy else "taqlid",
        "json": "json" if bor("json") else ("ujson" if bor("ujson") else "yo'q"),
        "vaqt_aniqligi": "ns" if imkon("_getframe") and bor("time") else "s",
        "xotira_olchovi": bool(imkon("getsizeof")),
        "iplar": bor("threading"),
        "saqlash": "sqlite3" if bor("sqlite3") else "fayl",
    }


def _import_mumkinmi(nom):
    try:
        __import__(nom)
        return True
    except ImportError:
        return False


class Yigʻuvchi:
    """Muhitga moslashadigan sensor yig'uvchi."""

    def __init__(self, muhit, bufer_hajmi=4):
        self.muhit = muhit
        self.bufer = []
        self.bufer_hajmi = bufer_hajmi
        self.yozilgan = []

    def olch(self, qiymat):
        self.bufer.append(round(qiymat, 2))
        if len(self.bufer) >= self.bufer_hajmi:
            self.yuborish()

    def yuborish(self):
        if not self.bufer:
            return
        if self.muhit["json"] != "yo'q":
            import json
            yuk = json.dumps({"qiymatlar": self.bufer})
        else:
            yuk = "|".join(str(q) for q in self.bufer)      # JSON bo'lmasa — oddiy format
        self.yozilgan.append((self.muhit["saqlash"], yuk))
        self.bufer = []          # yangi ro'yxat emas, tozalash ham mumkin — MicroPython'da xotira muhim


SERVER = None
MIKRO = ({"ujson", "time", "machine"}, set())
BRAUZER = ({"json", "time", "asyncio"}, {"getsizeof"})
MINIMAL = ({"time", "machine"}, set())          # JSON umuman yo'q port

print("=== 1. Muhitlar ===")
muhitlar = {
    "CPython (haqiqiy)": muhit_yasa(),
    "MicroPython (taqlid)": muhit_yasa(*MIKRO),
    "Pyodide (taqlid)": muhit_yasa(*BRAUZER),
    "Minimal port (taqlid)": muhit_yasa(*MINIMAL),
}
for nom, m in muhitlar.items():
    print(f"  {nom:22} json={m['json']:5} xotira_olchovi={str(m['xotira_olchovi']):5} iplar={str(m['iplar']):5} saqlash={m['saqlash']}")

print("\n=== 2. Bir xil kod, to'rt muhit ===")
for nom, m in muhitlar.items():
    yigʻuvchi = Yigʻuvchi(m)
    for i in range(6):
        yigʻuvchi.olch(20 + i * 0.75)
    yigʻuvchi.yuborish()
    print(f"  {nom:22} {len(yigʻuvchi.yozilgan)} paket, birinchisi: {yigʻuvchi.yozilgan[0][1][:44]}")

print("\n=== 3. Qaysi qismlar ko'chuvchan emas ===")
tekshiruvlar = [
    ("sys.getsizeof bilan bufer hajmi", hasattr(sys, "getsizeof")),
    ("threading bilan fon yuborish", _import_mumkinmi("threading")),
    ("sqlite3 bilan saqlash", _import_mumkinmi("sqlite3")),
    ("f-string va dataclass", sys.version_info >= (3, 7)),
]
for tavsif, mavjud in tekshiruvlar:
    holat = "bor" if mavjud else "yoq"
    print(f"  {tavsif:34} CPython muhitida {holat}; cheklangan muhitda muqobil kerak")

Natijaning muhim qismi:

text
=== 1. Muhitlar ===
  CPython (haqiqiy)      json=json  xotira_olchovi=True  iplar=True  saqlash=sqlite3
  MicroPython (taqlid)   json=ujson xotira_olchovi=False iplar=False saqlash=fayl
  Pyodide (taqlid)       json=json  xotira_olchovi=True  iplar=False saqlash=fayl
  Minimal port (taqlid)  json=yo'q  xotira_olchovi=False iplar=False saqlash=fayl

=== 2. Bir xil kod, to'rt muhit ===
  CPython (haqiqiy)      2 paket, birinchisi: {"qiymatlar": [20.0, 20.75, 21.5, 22.25]}
  MicroPython (taqlid)   2 paket, birinchisi: {"qiymatlar": [20.0, 20.75, 21.5, 22.25]}
  Pyodide (taqlid)       2 paket, birinchisi: {"qiymatlar": [20.0, 20.75, 21.5, 22.25]}
  Minimal port (taqlid)  2 paket, birinchisi: 20.0|20.75|21.5|22.25

=== 3. Qaysi qismlar ko'chuvchan emas ===
  sys.getsizeof bilan bufer hajmi    CPython muhitida bor; cheklangan muhitda muqobil kerak
  threading bilan fon yuborish       CPython muhitida bor; cheklangan muhitda muqobil kerak
  sqlite3 bilan saqlash              CPython muhitida bor; cheklangan muhitda muqobil kerak
  f-string va dataclass              CPython muhitida bor; cheklangan muhitda muqobil kerak

Nima ko'rsatdi: 2.5, 2.6-bo'limlar — muhitni bir joyda aniqlab, qolgan kodni o'zgarishsiz qoldirish mumkin.


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

Noto'g'ri fikr To'g'risi
"Python = CPython" Python — spetsifikatsiya; CPython — bitta implementatsiya
"PyPy hamma kodni tezlashtiradi" Sof Python sikllarda; C kengaytmalarda sekinlashtirishi mumkin
"PyPy'da GIL yo'q" Bor
"MicroPython — kichikroq CPython" Boshqa implementatsiya: kutubxona va turlar cheklangan
"Kodim ko'chuvchan, chunki faqat standart kutubxona" __del__, is, getsizeof kabi farazlar ko'chmaydi
"sys.implementation.name tekshiruvi yetarli" Imkoniyatni tekshirish ishonchliroq
"Pyodide — sekin o'yinchoq" Brauzerda to'liq ilmiy stek ishlaydi
"Cython va PyPy — bir xil yechim" Cython — kompilyator, PyPy — alohida interpretator

6. Keng tarqalgan xatolar va yechimlari

1. Faylni __del__ ga ishonib yopish

python
def oqi(yol):
    return open(yol).read()                 # ❌ PyPy'da deskriptor ochiq qoladi
with open(yol) as f:
    return f.read()                         # ✅

2. sys.getrefcount ga tayangan mantiq

python
if sys.getrefcount(obj) == 2:               # ❌ boshqa implementatsiyada yo'q
if havola() is None:                        # ✅ weakref

3. is bilan qiymat taqqoslash

python
if javob is "ha":                           # ❌
if javob == "ha":                           # ✅

4. GIL atomarligiga tayanish

python
self.hisob += 1                             # ❌ boshqa implementatsiyada va erkin ipli yig'mada
with self.qulf:
    self.hisob += 1                         # ✅

5. PyPy'ni qisqa skriptlarda sinash

bash
pypy skript.py                              # ⚠️ isitish ulgurmaydi — noto'g'ri xulosa

Real yuk bilan, uzoq ishlaydigan rejimda o'lchang.

6. MicroPython uchun katta kutubxonalarni import qilish

python
import pandas as pd                          # ❌ mikrokontrollerda yo'q

Oddiy tuzilmalar va array; og'ir hisobni serverga yuboring.

7. C kengaytmalarni PyPy'da "shunchaki ishlatish"

python
# ⚠️ cpyext orqali ishlaydi, lekin sekin — muqobil sof Python kutubxona qidiring

8. id() ni manzil deb hisoblash

python
korsatkich = id(obj)                        # ❌ faqat CPython'da manzil

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 11.2-dars (o'tilgan): is va ==
  • 11.4-dars (o'tilgan): __del__ va resurslarni yopish
  • 11.7-dars (o'tilgan): interning — implementatsiya tafsiloti
  • 12.4-dars (o'tilgan): C API va kengaytmalar
  • 12.5–12.6-darslar (o'tilgan): GIL va strategiyalar
  • 12.8-dars: CPython 3.11+ tezlik yaxshilanishlari — JIT g'oyalari
  • 17-qism: testlarni bir nechta muhitda o'tkazish
  • 19-qism: paketlash: wheel, abi3, PyPy uchun paketlar
  • 26-qism: IoT va avtomatlashtirish — MicroPython
  • 30-qism: Cython, Nuitka, boshqa tillar bilan integratsiya

8. Eng yaxshi amaliyotlar

  1. Spetsifikatsiyaga tayaning, implementatsiya tafsilotlariga emas.

  2. Resurslarni with yoki aniq close() bilan yoping.

  3. Imkoniyatni tekshiring (hasattr, try/import), nomni emas.

  4. Umumiy holatni qulf bilan himoyalang.

  5. PyPy ni real yuk bilan o'lchang — qisqa test aldaydi.

  6. Mikrokontroller kodida xotira ajratishni kamaytiring.

  7. CI da bir nechta implementatsiyani sinang (kutubxona yozayotgan bo'lsangiz).

  8. Implementatsiyaga bog'liq qismlarni bitta joyda saqlang (moslashuv qatlami).


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
import sys
import platform
1.  print(sys.implementation.name)
2.  print(platform.python_implementation())
3.  print(sys.implementation.name == platform.python_implementation().lower())
4.  print(hasattr(sys, "getrefcount"))
5.  print(sys.implementation.cache_tag.startswith("cpython"))
6.  print(type(sys.implementation.version).__name__)
7.  print(sys.version_info >= (3, 11))
8.  try:
        import ujson
        print("ujson")
    except ImportError:
        print("json")
9.  print(hasattr(sys, "_getframe"), hasattr(sys, "getsizeof"))
10. class K:
        pass
    k = K()
    print(id(k) == id(k))
11. import gc
    print(gc.isenabled())
12. print("pypy" in sys.version.lower())
Javoblar
  1. cpython
  2. CPython
  3. True
  4. True
  5. True
  6. sys.version_info turi — version_info
  7. True
  8. json — ujson odatda o'rnatilmagan
  9. True True
  10. True
  11. True
  12. False

Vazifa 2: Xatolarni tuzating

python
1.  class Ulanish:
        def __init__(self, manzil):
            self.s = ochish(manzil)
        def __del__(self):
            self.s.close()

2.  def sozlama():
        matn = open("sozlama.json").read()
        return json.loads(matn)

3.  def implementatsiya_tekshir():
        if sys.implementation.name != "cpython":
            raise RuntimeError("faqat CPython")
        return sys.getsizeof(KESH)

4.  def kutubxona_yukla():
        import numpy as np
        return np.zeros(1000)          # MicroPython uchun ham mo'ljallangan modul

5.  hisoblagich = 0
    def oshir():
        global hisoblagich
        hisoblagich += 1               # ko'p ipli xizmat
Javoblar
python
1.  class Ulanish:
        def __init__(self, manzil):
            self.s = ochish(manzil)
            self._fin = weakref.finalize(self, self.s.close)   # zaxira
        def yop(self):
            self._fin()
        def __enter__(self):
            return self
        def __exit__(self, *xato):
            self.yop()

2.  def sozlama():
        with open("sozlama.json") as f:                        # aniq yopish
            return json.load(f)

3.  def kesh_hajmi(kesh):
        if hasattr(sys, "getsizeof"):                          # imkoniyat bo'yicha
            return sys.getsizeof(kesh)
        return len(kesh)                                       # taxminiy muqobil

4.  def kutubxona_yukla(uzunlik=1000):
        try:
            import numpy as np
            return np.zeros(uzunlik)
        except ImportError:
            from array import array
            return array("f", bytes(4 * uzunlik))              # cheklangan muhitda

5.  import threading
    _qulf = threading.Lock()
    hisoblagich = 0
    def oshir():
        global hisoblagich
        with _qulf:
            hisoblagich += 1

Vazifa 3: PyPy bilan tajriba

  1. PyPy ni o'rnating (pypy yoki uv python install pypy@3.11)
  2. Uchta yukni CPython va PyPy da o'lchang: sof Python sikl, json bilan ishlash, hashlib bilan xeshlash
  3. Har biri uchun isitish ta'sirini ko'rsating: birinchi 1 soniya va keyingi 10 soniya
  4. Natijalarni jadvalda ko'rsatib, qaysi yuk uchun PyPy mos kelishini tushuntiring
  5. Xotira sarfini ham solishtiring

Vazifa 4: Ko'chuvchanlik tekshiruvchisini kengaytirish

Misol 3 dagi vositani rivojlantiring:

  1. Butun papkani (rekursiv) tekshirsin, # noqa: portability izohini hurmat qilsin
  2. Yangi qoidalar: time.clock, os.fork, signal ga bog'liqlik, sys.setrecursionlimit
  3. Har topilma uchun tuzatish namunasini (fix-it) chiqarsin
  4. JSON va matn hisobot formatlarini qo'llab-quvvatlasin, xatolar bo'lsa chiqish kodi 1 bo'lsin
  5. O'z loyihangizga qo'llab, natijalarni tahlil qiling

Vazifa 5: MicroPython uchun qayta yozish

Server uchun yozilgan sensor modulini mikrokontroller uchun moslang:

  1. dataclass va typing ni oddiy sinf va izohlar bilan almashtiring
  2. json.dumps o'rniga oldindan ajratilgan bytearray ga yozadigan formatter yozing
  3. Xotira ajratishlar sonini tracemalloc bilan (CPython'da) o'lchab, kamaytiring
  4. Ikkala variant bir xil natija berishini testlar bilan tasdiqlang

Vazifa 6: Pyodide

  1. Oddiy hisob-kitob funksiyasini yozing va uni Pyodide (brauzer) da ishga tushiring
  2. JavaScript'dan Python funksiyasini chaqirib, natijani sahifada ko'rsating
  3. Fayl tizimi va tarmoq cheklovlarini hujjatlashtiring
  4. CPython va Pyodide dagi bir xil hisobning vaqtini solishtiring

Vazifa 7: O'ylash

JavaScript'da bir nechta dvigatel bor (V8, SpiderMonkey, JavaScriptCore) va ular bitta standart (ECMAScript) ga bo'ysunadi; Java'da JVM spetsifikatsiyasi va ko'plab implementatsiyalar mavjud; C da esa standart va o'nlab kompilyatorlar. Python'da spetsifikatsiya rasmiy standart emas — "CPython nima qilsa, shu". Bu yondashuvning afzalliklari va kamchiliklari nimada, va PyPy kabi implementatsiyalar uchun bu nimani anglatadi?

Javob

Qisqa javob: Python'da til hujjat va CPython manba kodi bilan belgilanadi; rasmiy standartlashtirish organi yo'q. Bu tez rivojlanishga imkon beradi, lekin boshqa implementatsiyalarni CPython ortidan quvishga majbur qiladi va "implementatsiya tafsiloti" bilan "til qoidasi" chegarasini xiralashtiradi.

1. Modellar

Ekotizim Standart Implementatsiyalar
JavaScript ECMAScript (TC39, yillik relizlar) V8, SpiderMonkey, JavaScriptCore
Java JLS + JVM spetsifikatsiyasi, TCK testlari HotSpot, OpenJ9, GraalVM
C / C++ ISO standarti GCC, Clang, MSVC
Python Til hujjati + PEP lar + CPython amaliyoti CPython, PyPy, MicroPython, GraalPy

2. Afzalliklari

  1. Tezkorlik: yangi xususiyat PEP va CPython implementatsiyasi bilan bir yilda yetib keladi (match, TaskGroup, PEP 649)
  2. Aniqlik: noaniq joyda "CPython qanday qiladi" degan javob bor
  3. Kam byurokratiya: kichik jamoa qaror qabul qiladi

3. Kamchiliklari

  1. Boshqa implementatsiyalar ortda: PyPy 3.11 ni qo'llab-quvvatlaganda CPython 3.14 chiqadi
  2. Chegara xiralashgan: ko'p kod "tasodifiy" CPython xulqiga tayanadi (refcount, interning)
  3. C API — yashirin standart: kengaytmalar CPython ichki tuzilishiga bog'lanadi; PyPy cpyext ni taqlid qilishga majbur
  4. Rasmiy muvofiqlik testi yo'q: "Python-mos" degani aniq o'lchanmaydi (CPython test to'plami norasmiy mezon)

4. PyPy uchun bu nimani anglatadi

  • CPython test to'plamini va real kutubxonalarni ishlatib moslikni tekshiradi
  • Ichki xulqlarni (masalan, sys.getsizeof, id()) o'z modeliga moslab, ba'zan umuman qo'llab-quvvatlamaydi
  • C kengaytmalar uchun cpyext — sekin va murakkab qatlam; shuning uchun sof Python kutubxonalar afzal
  • Har CPython relizidan keyin yangi xususiyatlarni qayta implementatsiya qilish kerak

5. Yaxshilanish yo'nalishlari

  • Stable ABI / Limited API 12.4-bob — kengaytmalarni ichki tuzilishdan ajratadi
  • HPy loyihasi — implementatsiyaga bog'liq bo'lmagan kengaytma API si
  • PEP larda "implementatsiya tafsiloti" ni aniq belgilash amaliyoti kuchaymoqda

6. Xulosa

  1. Python'da rasmiy standart yo'q — til CPython va hujjatlar bilan belgilanadi
  2. Bu tezkor rivojlanish beradi, lekin alternativ implementatsiyalarni qiyin ahvolga soladi
  3. Dasturchi uchun xulosa: hujjatda kafolatlangan xulqqa tayaning, "CPython'da ishlayapti" ga emas
  4. HPy va Stable ABI kabi tashabbuslar ekotizimni implementatsiyadan mustaqilroq qiladi

Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.


Xulosa

Bu darsda Python implementatsiyalari dunyosini ko'rib chiqdik.

Eng muhim uch fikr:

  1. Python — til, CPython — implementatsiya. PyPy izli JIT bilan uzoq ishlaydigan sof Python kodni bir necha barobar tezlashtiradi (lekin isitish kerak va C kengaytmalar sekin), MicroPython bir necha yuz kilobayt xotirada ishlaydi (kutubxonaning kichik qismi bilan), GraalPy JVM ekotizimiga, Pyodide esa brauzerga olib chiqadi. Cython va Nuitka — interpretator emas, kompilyatorlar.

  2. CPython'ga xos farazlar ko'chmaydi. Oxirgi havola ketishi bilan obyektning o'chishi (va shu bilan faylning yopilishi), id() ning manzil bo'lishi, satrlar interningi, list.append ning atomarligi, sys.getrefcount va ctypes — hammasi implementatsiya tafsiloti. Ko'chuvchan kod with/finalize, ==, qulflar va weakref ga tayanadi.

  3. Imkoniyatni tekshiring, nomni emas. sys.implementation.name faqat ma'lumot uchun; haqiqiy qaror hasattr va try/import bilan qabul qilinadi. Implementatsiyaga bog'liq qismlarni bitta moslashuv qatlamida saqlang — shunda bitta kod server, mikrokontroller va brauzerda ishlay oladi.

Keyingi darsda CPython'ning o'zi qanday tezlashayotganini ko'ramiz: 3.11 dagi ixtisoslashgan adaptiv interpretator, arzon freymlar, nol narxli istisnolar va 3.13+ dagi tajribaviy JIT.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
12.7-dars: Alternativ interpretatorlar: PyPy, MicroPython — IlmHamroh