Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Turlash modellari
- 2.2. Annotatsiyalar nima emas
- 2.3. Annotatsiyalar — oddiy ma'lumot
- 2.4. Duck typing va nominal turlash
- 2.5. Statik tekshiruvchilar
- 2.6. Qayerda annotatsiya eng foydali
- 2.7. Ish vaqtidagi tekshiruv
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Ish vaqti annotatsiyalarni tekshirmaydi
- Misol 2 — Annotatsiyalar — oddiy ma'lumot
- Misol 3 — Ish vaqtida tekshirish: qachon arzon, qachon qimmat
- Misol 4 — Amaliy: annotatsiya qamrovi
- 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
13.1-dars: Dinamik va statik turlash
13-QISM — TURLAR TIZIMI · 1-dars
1. Kirish va motivatsiya
Python — dinamik turlangan til: o'zgaruvchi turi oldindan e'lon qilinmaydi va ish vaqtida o'zgarishi mumkin. Bu tezkor yozishga imkon beradi, lekin xatolar ham ish vaqtigacha yashirinib turadi.
Real vaziyat. Xabarnoma servisida funksiya oluvchilar ro'yxatini kutardi:
def yuborish(oluvchilar, matn):
for manzil in oluvchilar:
jonat(manzil, matn)Yangi endpoint unga bitta manzilni satr sifatida uzatdi: yuborish("aziz@wisar.uz", matn). Xato chiqmadi — satr ham iteratsiyalanadi, shuning uchun servis "a", "z", "i", "z" ... manzillariga 16 ta buzuq xabar yubordi. Muammo faqat kechqurun, yetkazib berish xatolari hisobotida ko'rindi.
Bitta annotatsiya buni yozish paytidayoq ko'rsatardi:
def yuborish(oluvchilar: list[str], matn: str) -> int: ... Python annotatsiyalarni ish vaqtida tekshirmaydi — ular tashqi vositalar (mypy, pyright) va odamlar uchun. Shuning uchun "turlar bor" degani "xato bo'lmaydi" degani emas: turlar tizimi faqat siz uni ishlatganda foyda beradi.
Bu darsda:
- Dinamik, statik va bosqichma-bosqich (gradual) turlash
- Annotatsiyalar nima va nima emas
- Annotatsiyalar — ma'lumot:
__annotations__,annotationlib3.14-bob,get_type_hints - Kechiktirilgan hisoblash (PEP 649) va oldinga havolalar
- Duck typing va nominal turlash
- Ish vaqtidagi tekshiruv: qachon foydali, qachon ortiqcha
- Amaliy: annotatsiya qamrovini o'lchaydigan vosita
2. Nazariya — chuqur tushuntirish
2.1. Turlash modellari
| Model | Ma'nosi | Misollar |
|---|---|---|
| Dinamik | Tur qiymatga tegishli, ish vaqtida tekshiriladi | Python, Ruby, JavaScript |
| Statik | Tur o'zgaruvchiga tegishli, kompilyatsiyada tekshiriladi | Java, Go, Rust, C# |
| Kuchli (strong) | Turlar avtomatik aralashmaydi: 1 + "2" → xato |
Python |
| Kuchsiz (weak) | Avtomatik o'girish: 1 + "2" → "12" |
JavaScript, PHP |
Python — dinamik va kuchli: turlar ish vaqtida tekshiriladi, lekin o'z-o'zidan o'girilmaydi.
Bosqichma-bosqich turlash (gradual typing) — Python tanlagan uchinchi yo'l: annotatsiyalar ixtiyoriy; annotatsiyalangan qismlarni tashqi tekshiruvchi tekshiradi, qolgani dinamik qoladi.
2.2. Annotatsiyalar nima emas
def yosh_qosh(yosh: int) -> int:
return yosh + 1
yosh_qosh("yigirma") # TypeError — lekin annotatsiya tufayli emas!| Annotatsiya nima emas | Tafsilot |
|---|---|
| Ish vaqti tekshiruvi emas | Interpretator turlarni tekshirmaydi |
| Majburlash emas | Noto'g'ri tur uzatish mumkin |
| Tezlashtirish emas | CPython ulardan optimallashtirish uchun foydalanmaydi (12.8-dars) |
| Hujjat o'rnini bosuvchi emas | Ma'noni izohlash baribir kerak |
| Annotatsiya nima | Tafsilot |
|---|---|
| Statik tekshiruvchi uchun ma'lumot | mypy, pyright, ty, pyrefly |
| IDE uchun: avtoto'ldirish, refaktoring | Eng kunlik foyda |
| Hujjat | Imzoni o'qish osonlashadi |
| Ish vaqtidagi kutubxonalar uchun manba | pydantic, dataclasses, fastapi (13.8-dars) |
2.3. Annotatsiyalar — oddiy ma'lumot
def komissiya(summa: float, foiz: float = 2.0) -> float: ...
komissiya.__annotations__ # {'summa': float, 'foiz': float, 'return': float}| Joy | Qayerda saqlanadi |
|---|---|
| Funksiya | funksiya.__annotations__ |
| Klass maydonlari | Klass.__annotations__ |
| Modul o'zgaruvchilari | modul.__annotations__ |
Lokal o'zgaruvchi (x: int = 1) |
Hech qayerda — faqat kompilyator uchun |
3.14 (PEP 649, 749): annotatsiyalar kechiktirilgan hisoblanadi — funksiya __annotate__ orqali ular so'ralganda quriladi. Natijada import tezroq va oldinga havolalar (-> "Tugun") tabiiy ishlaydi.
import annotationlib
annotationlib.get_annotations(f) # qiymatlar
annotationlib.get_annotations(f, format=annotationlib.Format.STRING) # satrlar
annotationlib.get_annotations(f, format=annotationlib.Format.FORWARDREF) # hal qilinmaganlari ForwardRef
typing.get_type_hints(f) # satrlarni hal qiladi from __future__ import annotations — 3.14 gacha ishlatilgan yechim; yangi kodda kerak emas.
2.4. Duck typing va nominal turlash
def yoz(oqim):
oqim.write("salom") # "write metodi bo'lsa — yetarli"| Yondashuv | Savol | Python'da |
|---|---|---|
| Nominal | "Bu klass Oqim dan merosmi?" |
isinstance, klasslar |
| Strukturaviy (duck) | "Bu obyektda write bormi?" |
Protokollar (13.5-dars) |
Bosqichma-bosqich turlash ikkalasini ham qo'llab-quvvatlaydi: nominal uchun klasslar, strukturaviy uchun Protocol.
2.5. Statik tekshiruvchilar
| Vosita | Xususiyati |
|---|---|
| mypy | Etalon, PEP lar muallifi jamoasi, sekinroq |
| pyright (Pylance) | TypeScript'da, juda tez, VS Code'da sukut |
| ty, pyrefly | Rust'da yozilgan yangi avlod (2025), juda tez, rivojlanmoqda |
| pytype | Xulosa (inference) ga ko'proq tayanadi |
Ular kodni bajarmasdan tahlil qiladi (12.1-dars: AST). Qat'iylik darajasi sozlanadi: strict, disallow_untyped_defs va h.k. (13.7-dars).
2.6. Qayerda annotatsiya eng foydali
| Joy | Foyda |
|---|---|
| Ommaviy API (kutubxona, servis chegarasi) | Eng katta — ishlatuvchilar uchun |
| Murakkab ma'lumot tuzilmalari | dict[str, list[tuple[int, str]]] — o'qishni osonlashtiradi |
| Uzoq yashaydigan kod | Refaktoring xavfsizroq |
| Qisqa skript, tajriba | Kam — ixtiyoriy |
| Testlar | Odatda kerak emas (lekin fikstura imzolari foydali) |
Amaliy strategiya: chegaralardan boshlang — tashqi ma'lumot kirib keladigan funksiyalarni annotatsiyalang, ichkariga asta-sekin tarqating.
2.7. Ish vaqtidagi tekshiruv
Annotatsiyalarga qarab ish vaqtida tekshirish mumkin (isinstance, dekorator, pydantic), lekin:
| Foyda | Narx |
|---|---|
| Tashqi ma'lumotni ishonchli qilish (JSON, forma, API) | Har chaqiruvda tekshiruv vaqti |
| Xatoni manbaga yaqin joyda ushlash | list[int] kabi umumiy turlarni to'liq tekshirish qimmat |
Qoida: chegarada ish vaqtida validatsiya (13.8-dars), ichkarida statik tekshiruv.
3. Tez ma'lumotnoma
Annotatsiya sintaksisi
def f(a: int, b: str = "x", *sonlar: float, **qolgan: object) -> bool: ...
maydon: dict[str, int] = {}
NOMLAR: list[str] = []Ma'lumot sifatida
f.__annotations__ Klass.__annotations__ modul.__annotations__
typing.get_type_hints(f) satrlarni hal qiladi
annotationlib.get_annotations(f, format=Format.STRING | FORWARDREF | VALUE) # 3.14
inspect.signature(f)Qoidalar
ish vaqtida tekshirilmaydi → mypy / pyright
chegarada validatsiya → pydantic (13.8)
oldinga havola → "Tugun" yoki 3.14 da to'g'ridan-to'g'ri
faqat tekshiruvchi uchun import → if TYPE_CHECKING:4. Batafsil misollar
Misol 1 — Ish vaqti annotatsiyalarni tekshirmaydi
"""Satrni ro'yxat o'rniga uzatish: jim xato; xato qayerda ko'rinadi; kuchli turlash; duck typing."""
def yuborish(oluvchilar: list[str], matn: str) -> int:
"""Har bir manzilga xabar yuboradi va yuborilganlar sonini qaytaradi."""
yuborildi = 0
for manzil in oluvchilar:
if "@" not in manzil:
navbat_xato.append(manzil)
else:
navbat_ok.append(manzil)
yuborildi += 1
return yuborildi
navbat_ok: list[str] = []
navbat_xato: list[str] = []
print("=== 1. Annotatsiya majburlamaydi ===")
print(f" to'g'ri chaqiruv: {yuborish(['aziz@wisar.uz', 'dilnoza@wisar.uz'], 'salom')} ta xabar")
print(f" navbatlar: ok={len(navbat_ok)}, xato={len(navbat_xato)}")
navbat_ok.clear()
navbat_xato.clear()
soni = yuborish("aziz@wisar.uz", "salom") # ❌ list emas, str uzatildi
print(f" yuborish('aziz@wisar.uz', ...) xato bermadi: {soni} ta 'xabar'")
print(f" navbatlar: ok={len(navbat_ok)}, xato={len(navbat_xato)} — har harf alohida 'manzil' bo'ldi")
print(f" birinchi uchtasi: {navbat_xato[:3]}")
print(" ⚠️ satr ham iteratsiyalanadi — shuning uchun xato jim o'tdi")
print("\n=== 2. Xato ancha keyin ko'rinadi ===")
def hisobot(manzillar: list[str]) -> str:
domenlar = {m.split("@")[1] for m in manzillar}
return f"{len(manzillar)} ta xabar, domenlar: {sorted(domenlar)}"
try:
print(hisobot(navbat_xato))
except IndexError as xato:
print(f" IndexError: {xato}")
print(" ⭐ xato manbai — yuborish() chaqiruvi, lekin u hisobot bosqichida chiqdi")
print("\n=== 3. Python kuchli turlangan ===")
for ifoda, amal in [("1 + '2'", lambda: 1 + "2"), ("'2' * 3", lambda: "2" * 3), ("[1] + (2,)", lambda: [1] + (2,))]:
try:
print(f" {ifoda:12} → {amal()!r}")
except TypeError as xato:
print(f" {ifoda:12} → TypeError: {xato}")
print("\n=== 4. Duck typing ===")
class Fayl:
def __init__(self):
self.yozilgan = []
def write(self, matn):
self.yozilgan.append(matn)
class Tarmoq:
def __init__(self):
self.paketlar = []
def write(self, matn):
self.paketlar.append(matn.encode())
def jurnalga_yoz(oqim, xabar):
"""Tur emas, xulq muhim: write() bo'lsa yetarli."""
oqim.write(xabar)
f, tarmoq = Fayl(), Tarmoq()
jurnalga_yoz(f, "boshlandi")
jurnalga_yoz(tarmoq, "boshlandi")
print(f" ikki xil klass, bitta funksiya: {f.yozilgan}, {tarmoq.paketlar}")
class Sanoq:
pass
try:
jurnalga_yoz(Sanoq(), "salom")
except AttributeError as xato:
print(f" write yo'q bo'lsa: AttributeError: {xato}")Natijaning muhim qismi:
=== 1. Annotatsiya majburlamaydi ===
to'g'ri chaqiruv: 2 ta xabar
navbatlar: ok=2, xato=0
yuborish('aziz@wisar.uz', ...) xato bermadi: 13 ta 'xabar'
navbatlar: ok=1, xato=12 — har harf alohida 'manzil' bo'ldi
birinchi uchtasi: ['a', 'z', 'i']
⚠️ satr ham iteratsiyalanadi — shuning uchun xato jim o'tdi
=== 2. Xato ancha keyin ko'rinadi ===
IndexError: list index out of range
⭐ xato manbai — yuborish() chaqiruvi, lekin u hisobot bosqichida chiqdi
=== 3. Python kuchli turlangan ===
1 + '2' → TypeError: unsupported operand type(s) for +: 'int' and 'str'
'2' * 3 → '222'
[1] + (2,) → TypeError: can only concatenate list (not "tuple") to list
=== 4. Duck typing ===
ikki xil klass, bitta funksiya: ['boshlandi'], [b'boshlandi']
write yo'q bo'lsa: AttributeError: 'Sanoq' object has no attribute 'write'Nima ko'rsatdi: 2.1, 2.2, 2.4-bo'limlar — annotatsiya bor edi, lekin uni hech kim tekshirmadi; xato esa manbadan uzoqda chiqdi.
Misol 2 — Annotatsiyalar — oddiy ma'lumot
"""__annotations__; lokal o'zgaruvchi annotatsiyasi saqlanmaydi; oldinga havolalar; annotationlib formatlari 3.14-bob; get_type_hints; signature."""
import annotationlib
import inspect
import typing
def buyurtma(mijoz: str, soni: int = 1, *qoshimcha: float, yetkazish: "Manzil | None" = None) -> "Chek":
jami: float = soni * 12_000.0 # lokal annotatsiya
return jami
class Manzil:
shahar: str
kocha: str = "noma'lum"
class Chek:
raqam: int
manzil: "Manzil"
print("=== 1. Funksiya annotatsiyalari ===")
for nom, qiymat in buyurtma.__annotations__.items():
print(f" {nom:12} {qiymat!r}")
print(f" lokal 'jami' annotatsiyasi saqlanganmi: {'jami' in buyurtma.__annotations__}")
print("\n=== 2. Klass va modul ===")
print(f" Manzil.__annotations__: {Manzil.__annotations__}")
print(f" sukut qiymat alohida: Manzil.kocha = {Manzil.kocha!r}, 'shahar' atributi bormi: {hasattr(Manzil, 'shahar')}")
print(f" modul darajasidagi annotatsiyalar mavjud: {hasattr(__import__('sys').modules['__main__'], '__annotations__')}")
print("\n=== 3. 3.14: kechiktirilgan hisoblash ===")
print(f" __annotate__ funksiyasi bor: {hasattr(buyurtma, '__annotate__')}")
satrlar = annotationlib.get_annotations(buyurtma, format=annotationlib.Format.STRING)
print(f" STRING format: {satrlar}")
qiymatlar = annotationlib.get_annotations(buyurtma)
print(f" VALUE format: mijoz={qiymatlar['mijoz'].__name__}, return={qiymatlar['return']!r}")
print("\n=== 4. Oldinga havolalar ===")
print(f" Chek.__annotations__: {Chek.__annotations__}")
hal_qilingan = typing.get_type_hints(Chek)
print(f" get_type_hints hal qildi: {{'raqam': {hal_qilingan['raqam'].__name__}, 'manzil': {hal_qilingan['manzil'].__name__}}}")
def noaniq(x: "HaliYoq") -> None:
return None
try:
typing.get_type_hints(noaniq)
except NameError as xato:
print(f" mavjud bo'lmagan turga havola: NameError: {xato}")
fr = annotationlib.get_annotations(noaniq, format=annotationlib.Format.FORWARDREF)
print(f" FORWARDREF format xato bermaydi: {fr}")
print("\n=== 5. inspect.signature ===")
imzo = inspect.signature(buyurtma)
print(f" imzo: {imzo}")
for nom, p in imzo.parameters.items():
print(f" {nom:12} turi: {p.annotation!r}, sukut: {p.default!r}, ko'rinishi: {p.kind.name}")Natijaning muhim qismi:
=== 1. Funksiya annotatsiyalari ===
mijoz <class 'str'>
soni <class 'int'>
qoshimcha <class 'float'>
yetkazish 'Manzil | None'
return 'Chek'
lokal 'jami' annotatsiyasi saqlanganmi: False
=== 2. Klass va modul ===
Manzil.__annotations__: {'shahar': <class 'str'>, 'kocha': <class 'str'>}
sukut qiymat alohida: Manzil.kocha = "noma'lum", 'shahar' atributi bormi: False
modul darajasidagi annotatsiyalar mavjud: True
=== 3. 3.14: kechiktirilgan hisoblash ===
__annotate__ funksiyasi bor: True
STRING format: {'mijoz': 'str', 'soni': 'int', 'qoshimcha': 'float', 'yetkazish': 'Manzil | None', 'return': 'Chek'}
VALUE format: mijoz=str, return='Chek'
=== 4. Oldinga havolalar ===
Chek.__annotations__: {'raqam': <class 'int'>, 'manzil': 'Manzil'}
get_type_hints hal qildi: {'raqam': int, 'manzil': Manzil}
mavjud bo'lmagan turga havola: NameError: name 'HaliYoq' is not defined
FORWARDREF format xato bermaydi: {'x': 'HaliYoq', 'return': None}
=== 5. inspect.signature ===
imzo: (mijoz: str, soni: int = 1, *qoshimcha: float, yetkazish: 'Manzil | None' = None) -> 'Chek'
mijoz turi: <class 'str'>, sukut: <class 'inspect._empty'>, ko'rinishi: POSITIONAL_OR_KEYWORD
soni turi: <class 'int'>, sukut: 1, ko'rinishi: POSITIONAL_OR_KEYWORD
qoshimcha turi: <class 'float'>, sukut: <class 'inspect._empty'>, ko'rinishi: VAR_POSITIONAL
yetkazish turi: 'Manzil | None', sukut: None, ko'rinishi: KEYWORD_ONLYNima ko'rsatdi: 2.3-bo'lim.
Misol 3 — Ish vaqtida tekshirish: qachon arzon, qachon qimmat
"""Annotatsiyaga qarab tekshiradigan dekorator; oddiy va umumiy turlar; narxi; chegarada tekshirish g'oyasi."""
import functools
import time
import typing
def turlarni_tekshir(funksiya):
"""Oddiy tekshiruvchi: faqat isinstance bilan tekshirib bo'ladigan turlar."""
izohlar = typing.get_type_hints(funksiya)
@functools.wraps(funksiya)
def orov(*args, **kwargs):
imzo = list(funksiya.__code__.co_varnames[:funksiya.__code__.co_argcount])
for nom, qiymat in list(zip(imzo, args)) + list(kwargs.items()):
kutilgan = izohlar.get(nom)
if isinstance(kutilgan, type) and not isinstance(qiymat, kutilgan):
raise TypeError(f"{funksiya.__name__}(): {nom} uchun {kutilgan.__name__} kutildi, {type(qiymat).__name__} keldi")
natija = funksiya(*args, **kwargs)
qaytish = izohlar.get("return")
if isinstance(qaytish, type) and not isinstance(natija, qaytish):
raise TypeError(f"{funksiya.__name__}(): {qaytish.__name__} qaytishi kerak edi, {type(natija).__name__} qaytdi")
return natija
return orov
@turlarni_tekshir
def chegirma(narx: float, foiz: int) -> float:
return narx * (100 - foiz) / 100
print("=== 1. Chegarada ushlash ===")
print(f" to'g'ri: chegirma(10_000.0, 15) = {chegirma(10_000.0, 15)}")
for args in [("10000", 15), (10_000.0, "15")]:
try:
chegirma(*args)
except TypeError as xato:
print(f" {args} → TypeError: {xato}")
print("\n=== 2. Umumiy turlarni isinstance tekshira olmaydi ===")
def ballar(qiymatlar: list[int]) -> float:
return sum(qiymatlar) / len(qiymatlar)
izohlar = typing.get_type_hints(ballar)
print(f" annotatsiya: {izohlar['qiymatlar']}")
print(f" isinstance([1, 2], list[int]) ni to'g'ridan-to'g'ri ishlatib bo'ladimi:", end=" ")
try:
isinstance([1, 2], izohlar["qiymatlar"])
print("ha")
except TypeError as xato:
print(f"yo'q — TypeError: {xato}")
print(f" faqat asosini tekshirish mumkin: isinstance([1, 2], {typing.get_origin(izohlar['qiymatlar']).__name__}) = "
f"{isinstance([1, 2], typing.get_origin(izohlar['qiymatlar']))}")
print(f" elementlarni tekshirish — har element uchun sikl: {all(isinstance(x, int) for x in [1, 2, 3])}")
print("\n=== 3. Narxi ===")
def toza(narx: float, foiz: int) -> float:
return narx * (100 - foiz) / 100
tekshiruvli = turlarni_tekshir(toza)
def olch(f, takror=200_000, urinish=3):
eng = float("inf")
for _ in range(urinish):
bosh = time.perf_counter()
for _ in range(takror):
f(10_000.0, 15)
eng = min(eng, time.perf_counter() - bosh)
return eng
t_toza, t_tekshiruvli = olch(toza), olch(tekshiruvli)
print(f" natijalar bir xil: {toza(10_000.0, 15) == tekshiruvli(10_000.0, 15)}")
print(f" tekshiruvli variant kamida 2 barobar sekin: {t_tekshiruvli / t_toza >= 2}")
print(" ⭐ shuning uchun: chegarada (API, fayl, forma) tekshiring, ichki issiq funksiyalarda emas")Natijaning muhim qismi:
=== 1. Chegarada ushlash ===
to'g'ri: chegirma(10_000.0, 15) = 8500.0
('10000', 15) → TypeError: chegirma(): narx uchun float kutildi, str keldi
(10000.0, '15') → TypeError: chegirma(): foiz uchun int kutildi, str keldi
=== 2. Umumiy turlarni isinstance tekshira olmaydi ===
annotatsiya: list[int]
isinstance([1, 2], list[int]) ni to'g'ridan-to'g'ri ishlatib bo'ladimi: yo'q — TypeError: isinstance() argument 2 cannot be a parameterized generic
faqat asosini tekshirish mumkin: isinstance([1, 2], list) = True
elementlarni tekshirish — har element uchun sikl: True
=== 3. Narxi ===
natijalar bir xil: True
tekshiruvli variant kamida 2 barobar sekin: True
⭐ shuning uchun: chegarada (API, fayl, forma) tekshiring, ichki issiq funksiyalarda emasNima ko'rsatdi: 2.2, 2.7-bo'limlar.
Misol 4 — Amaliy: annotatsiya qamrovi
Katta loyihaga turlarni bosqichma-bosqich kiritishda savol tug'iladi: qayerdan boshlash? Vosita modulni AST bilan tahlil qilib, qaysi funksiyalar annotatsiyalanmaganini, ular necha marta chaqirilishini (ya'ni qanchalik "markaziy" ekanini) va ommaviy API ekanini hisoblab, ustuvorlik ro'yxatini beradi.
"""AST: funksiyalar va ularning annotatsiya qamrovi; ommaviy/ichki; chaqiruvlar soni bo'yicha ustuvorlik; hisobot."""
import ast
from collections import Counter
MANBA = '''
"""To'lov moduli."""
from decimal import Decimal
SOLIQ = Decimal("0.12")
def komissiya(summa):
return summa * Decimal("0.02")
def _yaxlitla(qiymat: Decimal) -> Decimal:
return round(qiymat, 2)
def hisobla(summa: Decimal, foiz: Decimal) -> Decimal:
return _yaxlitla(summa * foiz + komissiya(summa))
def hisobot(buyurtmalar):
jami = Decimal(0)
for b in buyurtmalar:
jami += hisobla(b["summa"], SOLIQ) + komissiya(b["summa"])
return _yaxlitla(jami)
class Hisob:
def __init__(self, egasi, balans=Decimal(0)):
self.egasi = egasi
self.balans = balans
def yech(self, summa: Decimal) -> bool:
if summa > self.balans:
return False
self.balans -= summa + komissiya(summa)
return True
'''
def qamrov(manba):
daraxt = ast.parse(manba)
chaqiruvlar = Counter(t.func.id for t in ast.walk(daraxt) if isinstance(t, ast.Call) and isinstance(t.func, ast.Name))
hisobot = []
for tugun in ast.walk(daraxt):
if not isinstance(tugun, (ast.FunctionDef, ast.AsyncFunctionDef)):
continue
argumentlar = [a for a in tugun.args.args + tugun.args.kwonlyargs if a.arg not in {"self", "cls"}]
izohlangan = sum(a.annotation is not None for a in argumentlar)
jami = len(argumentlar) + 1 # + qaytish qiymati
bor = izohlangan + (tugun.returns is not None)
hisobot.append({
"nom": tugun.name,
"qator": tugun.lineno,
"ommaviy": not tugun.name.startswith("_"),
"qamrov": bor / jami,
"chaqiruvlar": chaqiruvlar.get(tugun.name, 0),
})
return hisobot
def ustuvorlik(yozuv):
"""Qamrovi past, ko'p chaqiriladigan va ommaviy funksiyalar birinchi."""
return (yozuv["qamrov"], -yozuv["chaqiruvlar"], not yozuv["ommaviy"])
yozuvlar = qamrov(MANBA)
print("=== 1. Funksiyalar bo'yicha qamrov ===")
print(f" {'funksiya':14} {'qator':>5} {'ommaviy':>8} {'qamrov':>7} {'chaqiruvlar':>11}")
for y in sorted(yozuvlar, key=lambda y: y["qator"]):
print(f" {y['nom']:14} {y['qator']:>5} {str(y['ommaviy']):>8} {y['qamrov']:>6.0%} {y['chaqiruvlar']:>11}")
jami_qamrov = sum(y["qamrov"] for y in yozuvlar) / len(yozuvlar)
print(f"\n modul bo'yicha o'rtacha qamrov: {jami_qamrov:.0%}")
print(f" to'liq annotatsiyalangan funksiyalar: {sum(1 for y in yozuvlar if y['qamrov'] == 1)} / {len(yozuvlar)}")
print("\n=== 2. Nimadan boshlash kerak ===")
for orin, y in enumerate(sorted(yozuvlar, key=ustuvorlik)[:3], 1):
sabab = []
if y["qamrov"] == 0:
sabab.append("umuman annotatsiyasiz")
if y["chaqiruvlar"] >= 2:
sabab.append(f"{y['chaqiruvlar']} joyda chaqiriladi")
if y["ommaviy"]:
sabab.append("ommaviy API")
print(f" {orin}. {y['nom']} (qator {y['qator']}) — {', '.join(sabab)}")
print("\n=== 3. Tavsiya ===")
print(" ⭐ chegaradagi va ko'p chaqiriladigan funksiyalardan boshlang")
print(" ⭐ har bosqichda tekshiruvchini ishga tushiring (13.7-dars), qamrovni CI da kuzating")Natijaning muhim qismi:
=== 1. Funksiyalar bo'yicha qamrov ===
funksiya qator ommaviy qamrov chaqiruvlar
komissiya 7 True 0% 3
_yaxlitla 10 False 100% 2
hisobla 13 True 100% 1
hisobot 16 True 0% 0
__init__ 23 False 0% 0
yech 27 True 100% 0
modul bo'yicha o'rtacha qamrov: 50%
to'liq annotatsiyalangan funksiyalar: 3 / 6
=== 2. Nimadan boshlash kerak ===
1. komissiya (qator 7) — umuman annotatsiyasiz, 3 joyda chaqiriladi, ommaviy API
2. hisobot (qator 16) — umuman annotatsiyasiz, ommaviy API
3. __init__ (qator 23) — umuman annotatsiyasiz
=== 3. Tavsiya ===
⭐ chegaradagi va ko'p chaqiriladigan funksiyalardan boshlang
⭐ har bosqichda tekshiruvchini ishga tushiring (13.7-dars), qamrovni CI da kuzatingNima ko'rsatdi: 2.6-bo'lim.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Annotatsiya turlarni majburlaydi" | Ish vaqtida tekshirilmaydi |
| "Annotatsiyalar kodni tezlashtiradi" | CPython ulardan foydalanmaydi |
| "Python zaif turlangan" | Kuchli turlangan: 1 + "2" — xato |
| "Hamma joyga annotatsiya qo'yish kerak" | Chegaralar va murakkab joylar muhimroq |
"Annotatsiya bo'lsa mypy avtomatik ishlaydi" |
Uni alohida ishga tushirasiz (CI da) |
"x: int lokal o'zgaruvchi haqida ma'lumot saqlaydi" |
Saqlanmaydi — faqat tekshiruvchi ko'radi |
"Oldinga havola uchun from __future__ import annotations shart" |
3.14 da annotatsiyalar kechiktirilgan (PEP 649) |
| "Turlar bo'lsa testlar kerak emas" | Turlar mantiqiy xatolarni ushlamaydi |
6. Keng tarqalgan xatolar va yechimlari
1. Annotatsiyaga ishonib, kirishni tekshirmaslik
def narx_qoshish(narx: float) -> None: # ❌ tashqi JSON dan str kelishi mumkin
...
narx = float(sorov["narx"]) # ✅ chegarada o'girish yoki validatsiya (13.8)2. Ish vaqtida list[int] ni tekshirishga urinish
isinstance(x, list[int]) # ❌ TypeError
isinstance(x, list) and all(isinstance(i, int) for i in x) # ✅ (narxini biling)3. Har chaqiruvda get_type_hints
def orov(*a):
izohlar = typing.get_type_hints(f) # ❌ har chaqiruvda qayta hisoblash
izohlar = typing.get_type_hints(f) # ✅ dekorator yaratilganda bir marta4. Faqat tekshiruv uchun kerak modulni oddiy import qilish
from ogir_modul import Tur # ❌ ish vaqtida ham yuklanadi
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ogir_modul import Tur # ✅5. Any bilan hamma narsani "tuzatish"
def ishla(malumot: Any) -> Any: # ⚠️ tekshiruvchi hech narsa ayta olmaydi6. Annotatsiyani hujjat o'rniga qo'yish
def yubor(x: dict) -> bool: ... # ⚠️ qanday kalitlar? nima qaytadi?
def yubor(xabar: Xabar) -> bool: # ✅ aniq tur + docstring
"""True — yuborildi, False — navbatga qo'yildi."""7. Turlarni ish vaqtida hamma joyda tekshirish
@turlarni_tekshir # ⚠️ issiq funksiyada sezilarli narx
def kichik_yordamchi(x: int) -> int: ...8. Eski uslubdagi annotatsiyalar
from typing import List, Dict, Optional
def f(x: List[int]) -> Optional[Dict[str, int]]: ... # ⚠️ eskirgan uslub
def f(x: list[int]) -> dict[str, int] | None: ... # ✅ 3.10+ (13.2, 13.3-darslar)7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 7-qism (o'tilgan): funksiya imzolari va sukut qiymatlar
- 8.17-dars (o'tilgan):
dataclass— annotatsiyalar maydonlarni belgilaydi - 12.1-dars (o'tilgan): annotatsiyalar kompilyatsiyada qanday saqlanadi
- 13.2–13.6-darslar:
typingvositalari, generiklar, protokollar - 13.7-dars:
mypybilan tekshirish va CI - 13.8-dars: ish vaqtidagi validatsiya (
pydantic) - 17-qism: testlar va turlar birgalikda
- 20–21-qismlar: FastAPI va Django — annotatsiyalarga tayangan freymvorklar
8. Eng yaxshi amaliyotlar
Chegaralardan boshlang: ommaviy funksiyalar, servis kirish nuqtalari.
Zamonaviy sintaksis:
list[int],str | None(13.2–13.3-darslar).Annotatsiyaga ishonmang — chegarada validatsiya qiling.
Statik tekshiruvchini CI ga qo'shing — aks holda annotatsiyalar eskiradi.
TYPE_CHECKINGbilan og'ir importlarni ish vaqtidan chiqaring.Anyni oxirgi chora sifatida ishlating va izohlang.Qamrovni o'lchang (Misol 4) va bosqichma-bosqich oshiring.
Turlarni hujjat va testlar o'rnini bosuvchi deb hisoblamang.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
import typing
1. def f(a: int) -> str:
return a
print(f(5))
2. print(f.__annotations__)
3. def g(x: "int") -> "int":
return x
print(typing.get_type_hints(g))
4. def h():
y: int = 1
return y
print(h.__annotations__)
5. class K:
a: int
b: str = "x"
print(K.__annotations__)
6. print(hasattr(K, "a"), hasattr(K, "b"))
7. print(1 + True)
8. try:
print(1 + "2")
except TypeError:
print("TypeError")
9. print(isinstance(True, int))
10. print(type([1, 2]) is list, isinstance([1, 2], list))
11. try:
isinstance([1], list[int])
except TypeError:
print("TypeError")
12. import inspect
print(str(inspect.signature(f)))Javoblar
5— annotatsiya majburlamaydi{'a': <class 'int'>, 'return': <class 'str'>}{'x': <class 'int'>, 'return': <class 'int'>}— satrlar hal qilindi{}— lokal annotatsiya saqlanmaydi{'a': <class 'int'>, 'b': <class 'str'>}False True— faqat sukut qiymatli maydon atribut bo'ladi2—bool—intning vorisiTypeErrorTrueTrue TrueTypeError(a: int) -> str
Vazifa 2: Xatolarni tuzating
1. def narx_ol(sorov: dict) -> float:
return sorov["narx"] # JSON dan str kelishi mumkin
2. from ogir_kutubxona import Model
def bashorat(model: Model, x: list[float]) -> float:
...
3. import typing
def tekshir(f):
def orov(*a, **k):
izohlar = typing.get_type_hints(f)
...
return orov
4. from typing import List, Optional, Dict
def xarita(nomlar: List[str]) -> Optional[Dict[str, int]]:
...
5. def ishla(malumot: typing.Any) -> typing.Any:
return malumot["natija"]Javoblar
1. def narx_ol(sorov: dict) -> float:
return float(sorov["narx"]) # chegarada o'girish (yoki pydantic — 13.8)
2. from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ogir_kutubxona import Model # ish vaqtida yuklanmaydi
def bashorat(model: "Model", x: list[float]) -> float:
...
3. def tekshir(f):
izohlar = typing.get_type_hints(f) # bir marta, dekorator yaratilganda
def orov(*a, **k):
...
return orov
4. def xarita(nomlar: list[str]) -> dict[str, int] | None: # zamonaviy sintaksis
...
5. class Javob(typing.TypedDict): # 13.6-dars
natija: int
def ishla(malumot: Javob) -> int:
return malumot["natija"]Vazifa 3: Annotatsiya qamrovi vositasi
Misol 4 ni CLI vositasiga aylantiring:
- Papkani rekursiv aylanib, har fayl uchun qamrovni hisoblasin
- Umumiy qamrov foizini va eng past 20 funksiyani chiqarsin
--min-qamrov 0.8bayrog'i bilan chegaradan past bo'lsa chiqish kodi 1 bo'lsin (CI uchun)- Metodlar,
async def,*args/**kwargsva lambda larni to'g'ri hisoblasin - O'z loyihangizga qo'llang va natijani tahlil qiling
Vazifa 4: Ish vaqti tekshiruvchisi
Misol 3 dagi dekoratorni kengaytiring:
list[int],dict[str, float],X | Nonekabi umumiy turlarni qo'llab-quvvatlasin (typing.get_origin,get_args)- Tekshiruv chuqurligini cheklang (masalan, ro'yxatning faqat birinchi 10 elementi)
strict=Falserejimida faqat ogohlantirish (warnings) bersinfunctools.cachebilan izohlarni keshlang- Narxini o'lchang: tekshiruvsiz, sayoz va chuqur rejimlarda
Vazifa 5: annotationlib bilan tajriba
- Bitta funksiya uchun
VALUE,STRING,FORWARDREFformatlarini solishtiring - Mavjud bo'lmagan turga havola qilgan funksiyada har uch format qanday ishlashini ko'rsating
- Klass, modul va metodlar uchun ham qo'llang
from __future__ import annotationsbilan yozilgan faylda natija qanday farq qilishini tekshiring- Natijalarni jadvalda umumlashtiring
Vazifa 6: Xatolar tarixi
O'z loyihangiz (yoki ochiq kodli kichik loyiha) git tarixidan:
TypeError,AttributeError,KeyErrorni tuzatgan 10 ta kommitni toping- Har biri uchun: annotatsiya + statik tekshiruv bu xatoni ushlay olarmidi?
- Ushlay oladiganlar uchun kerakli annotatsiyani yozing
- Natijani "turlar tizimi qancha xatoni oldini olardi" hisoboti sifatida rasmiylashtiring
Vazifa 7: O'ylash
TypeScript JavaScript ustiga bosqichma-bosqich turlar qo'shgan va bugun katta loyihalarda deyarli standart; Ruby Sorbet va RBS bilan shu yo'ldan bordi; PHP esa turlarni ish vaqtida majburlaydigan e'lonlar qo'shdi. Python annotatsiyalarni ish vaqtida tekshirmaslikni tanladi. Bu tanlovning sabablari va oqibatlari nimada, va pydantic kabi kutubxonalarning mashhurligi bu haqda nima deydi?
Javob
Qisqa javob: Python annotatsiyalarni til darajasida tekshirmaslikni tanladi, chunki tekshirish har chaqiruvda narx qo'shadi, dinamik xulqni cheklaydi va ekotizimni bo'lib yuborardi. Natijada tekshirish vositalar (mypy, pyright) va kutubxonalar (pydantic) zimmasiga o'tdi — bu moslashuvchan, lekin "annotatsiya bor, demak tekshirilgan" degan noto'g'ri tasavvurni tug'diradi.
1. Yondashuvlar
| Til | Turlar qayerda tekshiriladi | Xususiyat |
|---|---|---|
| TypeScript | Kompilyatsiyada (transpilyatsiya), ish vaqtida yo'q | Python'ga eng yaqin model |
| Ruby (Sorbet/RBS) | Statik + ixtiyoriy ish vaqti (sig) |
Aralash |
| PHP 7+ | Ish vaqtida majburlaydi (skalyar turlar, strict_types) |
Xato darhol chiqadi |
| Java, Go, Rust | Kompilyatsiyada, ishga tushirilmaydi | To'liq statik |
| Python | Statik — tashqi vositalar; ish vaqtida — kutubxonalar | Bosqichma-bosqich |
2. Nega Python majburlamaydi
- Unumdorlik: har chaqiruvda
isinstance— issiq kodda sezilarli narx;list[int]ni to'liq tekshirish esa O(n) - Dinamizm: duck typing,
__getattr__, proksi obyektlar, mock lar — qat'iy tekshiruv ularni buzardi - Moslik: milliardlab qator mavjud kod annotatsiyasiz; majburiy tekshiruv ularni sindirardi
- Tanlov erkinligi: turli loyihalarga turli qat'iylik kerak —
mypy --strictdan to umuman tekshirmaslikgacha - Til vs kutubxona: Python falsafasi bo'yicha bunday siyosat vositalarga qoldiriladi
3. Oqibatlari
| Ijobiy | Salbiy |
|---|---|
| Annotatsiyalar tekin (3.14 da kechiktirilgan — import tez) | "Annotatsiya bor" ≠ "to'g'ri" |
| Har loyiha o'z qat'iyligini tanlaydi | Ekotizimda bir xillik yo'q |
| Kutubxonalar annotatsiyalardan foydalanadi (pydantic, FastAPI, dataclasses) | Ikki dunyo: statik va ish vaqti — ular mos kelmasligi mumkin |
| Dinamik naqshlar saqlanadi | CI ga qo'shilmasa, annotatsiyalar eskiradi |
4. pydantic nima haqida gapiradi
- Dasturchilarga chegarada ishonchli validatsiya kerak: JSON, forma, konfiguratsiya, API
- Annotatsiyalar bu ish uchun tabiiy manba bo'lib chiqdi — bir marta yozilgan tur ham statik, ham ish vaqti uchun ishlaydi
- FastAPI muvaffaqiyati shundan: bitta imzo → validatsiya + hujjat + IDE yordami
- Ya'ni til tekshirmasa ham, ekotizim tekshiruvni kerakli joyda tiklab oldi
5. Amaliy xulosa
- Ichkarida — statik tekshiruv (
mypy/pyright), CI da majburiy - Chegarada — ish vaqtidagi validatsiya (
pydantic, qo'lda o'girish) - Annotatsiyalarni "hujjat" emas, shartnoma deb qarang va ularni tekshiruvchi bilan tirik saqlang
- TypeScript tajribasi: bosqichma-bosqich joriy qilish ishlaydi — hammasini birdan emas
Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.
Xulosa
Bu darsda Python'ning turlash modelini va annotatsiyalarning o'rnini ko'rib chiqdik.
Eng muhim uch fikr:
Python — dinamik va kuchli turlangan, annotatsiyalar esa ixtiyoriy. Interpretator
def f(x: int)ni tekshirmaydi: noto'g'ri tur uzatilsa, xato ko'pincha ancha keyin va boshqa joyda chiqadi. Annotatsiyalar statik tekshiruvchilar (mypy,pyright), IDE, hujjat vapydantickabi kutubxonalar uchun ma'lumot beradi — ya'ni foyda siz ularni ishlatganingizda paydo bo'ladi.Annotatsiyalar — oddiy ma'lumot. Funksiya, klass va modul darajasida
__annotations__da saqlanadi (lokal o'zgaruvchilarniki — hech qayerda); 3.14 da ular kechiktirilgan hisoblanadi (PEP 649) vaannotationliborqaliVALUE,STRING,FORWARDREFformatlarida o'qiladi.typing.get_type_hintssatrlarni hal qiladi,inspect.signatureesa imzoni to'liq ko'rsatadi.Bosqichma-bosqich joriy qiling. Chegaradagi va ko'p chaqiriladigan funksiyalardan boshlang, qamrovni o'lchang, tekshiruvchini CI ga qo'shing. Ish vaqtidagi tekshiruv — chegarada (tashqi ma'lumot) o'rinli, issiq ichki funksiyalarda esa qimmat:
list[int]niisinstancebilan to'g'ridan-to'g'ri tekshirib ham bo'lmaydi.
Keyingi darsda typing modulining asoslarini o'rganamiz: zamonaviy sintaksis, kolleksiya turlari, Callable, Any va object farqi, turlar taxallusi (PEP 695) va imzolarni to'g'ri yozish.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!