Type hints — list[int], Optional, Union, dict[str, int], TypeVar

~15 daq · Python · Ilg'or mavzular

Muammodan boshlaylik

Hamkasbingiz yozgan funksiya:

def hisobla(m, c, d):
    ...

m nima — son? ro'yxat? dictionary? c — foiz yoki summa? Natija qanday? Javob olish uchun funksiya ichini o'qish kerak. Va xato faqat ishga tushirganda chiqadi:

hisobla("100000", 10, None)
# TypeError: can't multiply sequence by non-int of type 'float' — 200-qatorda, ishlab chiqarishda

Python dinamik tipli til — turlarni yozish shart emas. Lekin katta loyihada turlar hujjat va xatolarni erta topish vositasi.


Type hints nima?

Type hints — o'zgaruvchilar, parametrlar va qaytish qiymatining turini ko'rsatuvchi izohlar:

def chegirmali_narx(narx: int, foiz: float = 0.0) -> float:
    return narx * (1 - foiz / 100)
  • narx: int — parametr turi
  • -> float — qaytish qiymati turi
  • Funksiya imzosidan hamma narsa ko'rinadi

[!INFO] Type hints dastur ishlashiga ta'sir qilmaydi — Python ularni tekshirmaydi: chegirmali_narx("abc") baribir ishga tushadi (va xato beradi). Turlarni tekshiradi: muharrir (VS Code, PyCharm — qizil chiziq va avtomatik to'ldirish) va statik tahlil vositalari (mypy, pyright) — kodni ishga tushirmasdan.


Hayotiy o'xshatma

Elektr rozetkalari va vilkalarda belgilar: "220V", "16A". Ular tokning o'zini o'zgartirmaydi — lekin noto'g'ri qurilmani ulamaslikka yordam beradi. Elektrik (mypy) esa ulashdan oldin hamma narsani tekshirib chiqadi.


Oddiy turlar

ism: str = "Lola"
yosh: int = 20
reyting: float = 4.8
faol: bool = True

def salomlash(ism: str) -> str:
    return f"Salom, {ism}"

def log_yoz(xabar: str) -> None:      # hech narsa qaytarmaydi
    print(xabar)

Kolleksiyalar

Python 3.9+ da o'rnatilgan turlar bilan:

baholar: list[int] = [5, 4, 5]
narxlar: dict[str, int] = {"olma": 15000}
noyob: set[str] = {"a", "b"}
nuqta: tuple[float, float] = (41.29, 69.24)
qiymatlar: tuple[int, ...] = (1, 2, 3, 4)       # istalgan uzunlik

def ortacha(sonlar: list[float]) -> float:
    return sum(sonlar) / len(sonlar)

def guruhla(talabalar: list[dict[str, str]]) -> dict[str, list[str]]:
    ...

[!INFO] Eski kodda (Python 3.8 va undan oldin) from typing import List, Dict, Tuple va List[int] ko'rinishini uchratasiz. Hozir kichik harfli list[int], dict[str, int] — tavsiya etilgan.


Optional va Union

Bir nechta tur — |

def id_formatla(id_: int | str) -> str:
    return str(id_).zfill(6)

None bo'lishi mumkin

def foydalanuvchi_top(email: str) -> dict | None:
    for u in foydalanuvchilar:
        if u["email"] == email:
            return u
    return None

def salom(ism: str | None = None) -> str:
    return f"Salom, {ism or 'mehmon'}"

X | None — "X yoki None". Eski yozuv: Optional[X] yoki Union[X, None] (from typing import Optional, Union).

Natija | None bo'lsa, mypy uni ishlatishdan oldin tekshirishni talab qiladi:

u = foydalanuvchi_top("lola@mail.uz")
print(u["ism"])            # ❌ mypy: Value of type "dict | None" is not indexable
if u is not None:
    print(u["ism"])        # ✅

Bu — NoneType xatolarining ('NoneType' object is not subscriptable) katta qismini kod ishga tushmasdan oldin topadi.


Boshqa foydali turlar

from typing import Any, Literal, Callable, TypedDict
from collections.abc import Iterable, Iterator

def chop_et(x: Any) -> None: ...              # istalgan tur (tekshiruvni o'chiradi)

def tartibla(yonalish: Literal["osish", "kamayish"]) -> None: ...   # faqat shu qiymatlar

def qayta_urin(f: Callable[[int], str], marta: int) -> str: ...     # funksiya turi

def jami(sonlar: Iterable[int]) -> int:        # list, tuple, set, generator — hammasi
    return sum(sonlar)

def sanash(n: int) -> Iterator[int]:           # generator (45-dars)
    yield from range(n)

TypedDict — tuzilmali dictionary

from typing import TypedDict, NotRequired

class Talaba(TypedDict):
    ism: str
    yosh: int
    email: NotRequired[str]

t: Talaba = {"ism": "Lola", "yosh": 20}
t["yoshi"]        # ❌ mypy: TypedDict "Talaba" has no key "yoshi"

JSON API javoblari kabi dictionary lar uchun — kalitlar va turlar tekshiriladi.


O'z klasslaringiz

class BankHisobi:
    def __init__(self, egasi: str, balans: int = 0) -> None:
        self.egasi = egasi
        self.balans = balans

    def otkaz(self, boshqa: "BankHisobi", summa: int) -> bool:
        ...

def eng_boy(hisoblar: list[BankHisobi]) -> BankHisobi:
    return max(hisoblar, key=lambda h: h.balans)

Klass o'z ichida o'ziga murojaat qilsa — qo'shtirnoqda ("BankHisobi") yoki faylning boshida from __future__ import annotations. Python 3.11+ da — typing.Self.


TypeVar va generic lar

"Ro'yxatning birinchi elementini qaytaradi" — qanday tur?

def birinchi(royxat: list) -> object:    # ❌ tur ma'lumoti yo'qoladi
    return royxat[0]

TypeVar — "kirgan tur bilan bir xil tur":

from typing import TypeVar

T = TypeVar("T")

def birinchi(royxat: list[T]) -> T:
    return royxat[0]

a = birinchi([1, 2, 3])          # mypy biladi: a — int
b = birinchi(["x", "y"])         # b — str

Python 3.12+ da qisqaroq sintaksis:

def birinchi[T](royxat: list[T]) -> T:
    return royxat[0]

mypy — turlarni tekshirish

pip install mypy
mypy dastur.py
# dastur.py
def chegirmali_narx(narx: int, foiz: float) -> float:
    return narx * (1 - foiz / 100)

chegirmali_narx("100000", 10)
dastur.py:4: error: Argument 1 to "chegirmali_narx" has incompatible type "str"; expected "int"
Found 1 error in 1 file (checked 1 source file)

Xato — kod ishga tushirilmasdan, CI da (Express kursi, 67-dars kabi) avtomatik topiladi.

[!TIP] Turlarni bosqichma-bosqich qo'shing: avval funksiya imzolari (parametrlar va qaytish qiymati) — eng ko'p foyda shundan. Lokal o'zgaruvchilarga odatda yozish shart emas — tur avtomatik aniqlanadi (x = 5 — int). Pydantic, FastAPI kabi kutubxonalar esa type hints dan ishlash paytida validatsiya uchun ham foydalanadi.


Tez-tez uchraydigan xatolar

Type hints ni runtime tekshiruv deb o'ylash:

def f(x: int): return x * 2
f("ab")          # "abab" — Python hech narsa demaydi; mypy esa xato topadi

Standart qiymat None, tur esa None siz:

def f(ism: str = None): ...          # ❌ mypy xatosi
def f(ism: str | None = None): ...   # ✅

list ni element turisiz — list (nima ro'yxati?) o'rniga list[int].


Xulosa

Type hints — kodni o'z-o'zidan hujjatlashtiruvchi va xatolarni erta topishga yordam beruvchi izohlar.

Eslab qoling:

  • x: int, def f(a: str) -> bool:, -> None
  • list[int], dict[str, int], tuple[float, float], set[str]
  • int | str, X | None (= Optional[X]); None ni tekshirishga majbur qiladi
  • Literal, Callable, Iterable, Iterator, TypedDict, Any
  • TypeVar / def f[T](...) — generic funksiyalar
  • Python tekshirmaydi — mypy/pyright va muharrir tekshiradi

Keyingi dars

49-dars: Dataclasses — @dataclass, field, frozen, __post_init__