Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Zamonaviy sintaksis
- 2.2. Konkret va abstrakt kolleksiyalar
- 2.3. Callable
- 2.4. Any, object, Never, None
- 2.5. Turlar taxallusi (PEP 695)
- 2.6. Turlarni ish vaqtida tekshirish
- 2.7. Uslub: qanchalik aniq
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Zamonaviy sintaksis va kolleksiya turlari
- Misol 2 — Any, object, Never, None
- Misol 3 — Turlar taxallusi (PEP 695)
- Misol 4 — Amaliy: "bo'sh" annotatsiyalarni topuvchi
- 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.2-dars: typing asoslari
13-QISM — TURLAR TIZIMI · 2-dars
1. Kirish va motivatsiya
13.1-darsda annotatsiyalar nima ekanini ko'rdik. Endi ularni to'g'ri yozishni o'rganamiz.
Real vaziyat. Kutubxona funksiyasining imzosi shunday edi:
def guruhla(yozuvlar, kalit):
...Foydalanuvchilar savol berardi: yozuvlar — ro'yxatmi yoki generator ham bo'ladimi? kalit — satrmi yoki funksiyami? Nima qaytadi? Hujjatga uch abzats yozildi, savollar baribir tugamadi.
Bitta qator hammasini hal qildi:
def guruhla[T](yozuvlar: Iterable[T], kalit: Callable[[T], str]) -> dict[str, list[T]]:Endi IDE avtoto'ldirish beradi, tekshiruvchi noto'g'ri chaqiruvni ushlaydi va savollar yo'qoldi.
Yaxshi annotatsiya — shartnoma: nima qabul qilinadi, nima qaytadi. Uni yozishning zamonaviy usuli 2020-yillardagi Python'da ancha soddalashdi: typing.List va Optional o'rniga list va |.
Bu darsda:
- Zamonaviy sintaksis:
list[int],dict[str, int],str | None - Konkret va abstrakt kolleksiyalar:
listvaIterable,Sequence,Mapping Callable— funksiyalarni annotatsiyalash-
Any,object,Never,Nonefarqi - Turlar taxallusi: PEP 695
typesintaksisi get_type_hints,get_origin,get_args,assert_type,reveal_type- Amaliy: "bo'sh" annotatsiyalarni topuvchi vosita
2. Nazariya — chuqur tushuntirish
2.1. Zamonaviy sintaksis
| Eski (3.8 va oldin) | Zamonaviy | Qachondan |
|---|---|---|
List[int], Dict[str, int] |
list[int], dict[str, int] |
3.9 |
Tuple[int, ...], Set[str] |
tuple[int, ...], set[str] |
3.9 |
Optional[int] |
int | None |
3.10 |
Union[int, str] |
int | str |
3.10 |
Callable[[int], str] (typing dan) |
collections.abc.Callable[[int], str] |
3.9 |
TypeVar e'lonlari |
def f[T](...), class K[T] |
3.12 (13.4-dars) |
TypeAlias |
type Nom = ... |
3.12 (2.5) |
Yangi kodda typing.List, typing.Dict, Optional, Union kerak emas — ular faqat eski kodni qo'llab-quvvatlash uchun qoldirilgan.
def hisobot(
yozuvlar: list[dict[str, int]],
sarlavha: str | None = None,
teglar: tuple[str, ...] = (),
) -> dict[str, list[int]]: ...2.2. Konkret va abstrakt kolleksiyalar
from collections.abc import Iterable, Sequence, Mapping, Callable, Iterator| Kerak bo'lgan xulq | Tur |
|---|---|
| Faqat aylanib chiqish | Iterable[T] |
Aylanish + indeks + len |
Sequence[T] |
| Kalit bo'yicha o'qish | Mapping[K, V] |
| O'zgartirish ham kerak | list[T], dict[K, V], MutableMapping[K, V] |
| Iterator (bir martalik) | Iterator[T] |
Qoida: parametrda eng umumiy turni oling, qaytishda eng aniq turni bering.
def ortacha(qiymatlar: Iterable[float]) -> float: ... # ✅ list, tuple, generator — hammasi
def ortacha(qiymatlar: list[float]) -> float: ... # ⚠️ faqat ro'yxat
def nomlar() -> list[str]: ... # ✅ chaqiruvchi indekslay oladi
def nomlar() -> Iterable[str]: ... # ⚠️ ortiqcha cheklov str ham Iterable[str] — shuning uchun 13.1-darsdagi xato tekshiruvchida ham ushlanmasligi mumkin: Sequence[str] yoki list[str] aniqroq.
2.3. Callable
Callable[[int, str], bool] # (int, str) -> bool
Callable[[], None] # argumentsiz
Callable[..., int] # argumentlar ixtiyoriy, natija intMurakkab imzolar (*args, kalitli argumentlar) uchun Protocol (13.5-dars) yoki ParamSpec (13.4-dars).
2.4. Any, object, Never, None
| Tur | Ma'nosi | Qachon |
|---|---|---|
Any |
"Tekshirma" — har qanday amal ruxsat | Chegara, dinamik kod; kamdan-kam |
object |
"Har qanday obyekt" — lekin amallar cheklangan | Haqiqatan har narsa kelishi mumkin bo'lganda |
None |
None qiymati (qaytish uchun -> None) |
Qiymat qaytarmaydigan funksiya |
Never |
Hech qachon qiymat qaytmaydi | raise bilan tugaydigan funksiya |
LiteralString |
Faqat literal satrlar | SQL/shell in'yeksiyasidan himoya |
def xatoga_tushir(xabar: str) -> Never:
raise RuntimeError(xabar)
def chop(qiymat: object) -> None:
print(qiymat) # ✅ str(qiymat) ishlaydi
# qiymat + 1 # ❌ tekshiruvchi xato beradi — object da + yo'q Any — "tekshiruvni o'chirish" tugmasi: u bilan xatolar jim o'tadi. object esa xavfsiz: undan foydalanish uchun turni toraytirish kerak (13.3-dars).
2.5. Turlar taxallusi (PEP 695)
type Yol = str
type Sonlar = list[float]
type Jadval[T] = dict[str, list[T]] # generik taxallus
type Tugun = dict[str, "Tugun"] # rekursiv — kechiktirilgan hisoblashtype X = ...dangasa: o'ng tomon faqat kerak bo'lganda hisoblanadi — oldinga havolalar tabiiy ishlaydi- Natija —
TypeAliasTypeobyekti;X.__value__asl turni beradi - Eski uslub:
Yol = str(oddiy tayinlash) yokiYol: TypeAlias = str— hali ham ishlaydi
Taxalluslar domen tilini kodga olib kiradi: type FoydalanuvchiID = int — imzolarni o'qish osonlashadi (lekin turlar baribir bir xil; alohida tur kerak bo'lsa — NewType, 13.4-dars).
2.6. Turlarni ish vaqtida tekshirish
typing.get_type_hints(f) # satrlarni hal qilingan annotatsiyalar
typing.get_origin(list[int]) # list
typing.get_args(dict[str, int]) # (str, int)
typing.assert_type(x, list[int]) # tekshiruvchi uchun; ish vaqtida x ni qaytaradi
typing.reveal_type(x) # ⚠️ ish vaqtida stderr ga yozadireveal_type — tekshiruvchiga "bu yerda tur nima?" degan savol; mypy uni chiqarib beradi (13.7-dars). Kodda qoldirmang.
2.7. Uslub: qanchalik aniq
| Holat | Tavsiya |
|---|---|
| Ommaviy funksiya | To'liq annotatsiya |
dict[str, Any] bilan JSON |
Boshlanishiga mayli; keyin TypedDict (13.6-dars) |
| Ichki yordamchi | Qisqacha; xulosa (inference) ko'p ishni qiladi |
| Lokal o'zgaruvchi | Odatda kerak emas — tekshiruvchi o'zi aniqlaydi |
| Bo'sh konteyner | ballar: list[int] = [] — kerak, aks holda tur noma'lum |
3. Tez ma'lumotnoma
Sintaksis
list[int] dict[str, float] tuple[int, str] tuple[int, ...] set[str]
str | None int | str Callable[[int], str] Iterable[T] Sequence[T] Mapping[K, V]
type Nom = dict[str, int] type Juft[T] = tuple[T, T]Maxsus turlar
Any tekshiruvni o'chiradi object har narsa, amallar cheklangan
None qiymat yo'q Never qaytmaydi (raise)
LiteralString faqat literal satrIntrospeksiya
typing.get_type_hints(f) get_origin(t) get_args(t)
typing.assert_type(x, T) typing.reveal_type(x) # stderr
X.__value__ (TypeAliasType)4. Batafsil misollar
Misol 1 — Zamonaviy sintaksis va kolleksiya turlari
"""Eski va yangi sintaksis; builtin generiklar; abstrakt kolleksiyalar; Callable; get_origin/get_args bilan tahlil."""
import typing
from collections.abc import Callable, Iterable, Mapping, Sequence
def hisobot(
yozuvlar: list[dict[str, int]],
sarlavha: str | None = None,
teglar: tuple[str, ...] = (),
) -> dict[str, list[int]]:
natija: dict[str, list[int]] = {}
for y in yozuvlar:
for kalit, qiymat in y.items():
natija.setdefault(kalit, []).append(qiymat)
return natija
print("=== 1. Annotatsiyalar ko'rinishi ===")
for nom, tur in typing.get_type_hints(hisobot).items():
print(f" {nom:10} {tur}")
print(f" Optional[int] ko'rinishi: {typing.Optional[int]}, int | None bilan bir xil: {typing.Optional[int] == (int | None)}")
print(f" Union[int, str] ko'rinishi: {typing.Union[int, str]}, teng: {typing.Union[int, str] == (int | str)}")
print("\n=== 2. get_origin va get_args ===")
for tur in [list[int], dict[str, float], tuple[int, ...], str | None, Callable[[int, str], bool], Sequence[int]]:
asos = typing.get_origin(tur)
print(f" {str(tur):42} origin={getattr(asos, '__name__', asos)!s:12} args={typing.get_args(tur)}")
print("\n=== 3. Abstrakt va konkret ===")
def ortacha(qiymatlar: Iterable[float]) -> float:
royxat = list(qiymatlar)
return sum(royxat) / len(royxat)
def uchinchisi(qiymatlar: Sequence[float]) -> float:
return qiymatlar[2]
manbalar = {
"list": [1.0, 2.0, 3.0, 4.0],
"tuple": (1.0, 2.0, 3.0, 4.0),
"generator": (float(x) for x in range(1, 5)),
"range": range(1, 5),
}
for nom, manba in manbalar.items():
nusxa = list(manba) if nom == "generator" else manba
indekslanadi = isinstance(nusxa, Sequence)
print(f" {nom:10} Iterable: {isinstance(nusxa, Iterable)!s:5} Sequence: {indekslanadi!s:5} "
f"ortacha={ortacha(nusxa)} {'uchinchisi=' + str(uchinchisi(nusxa)) if indekslanadi else '(indekslanmaydi)'}")
print("\n=== 4. Callable ===")
def qolla(sonlar: Sequence[int], amal: Callable[[int], int]) -> list[int]:
return [amal(s) for s in sonlar]
print(f" kvadrat: {qolla([1, 2, 3], lambda x: x * x)}")
print(f" abs: {qolla([-1, -2, 3], abs)}")
print(f" Callable argumentlari: {typing.get_args(Callable[[int, str], bool])}")
print("\n=== 5. Mapping va o'zgartirish ===")
def kalitlar(xarita: Mapping[str, int]) -> list[str]:
return sorted(xarita)
def qoshib_yoz(xarita: dict[str, int], kalit: str, qiymat: int) -> None:
xarita[kalit] = qiymat
narxlar = {"olma": 12000, "nok": 15000}
print(f" Mapping (faqat o'qish) bilan: {kalitlar(narxlar)}")
qoshib_yoz(narxlar, "uzum", 21000)
print(f" dict (o'zgartirish) bilan: {narxlar}")
print(" ⭐ parametr faqat o'qilsa — Mapping/Sequence/Iterable; o'zgartirilsa — dict/list")Natijaning muhim qismi:
=== 1. Annotatsiyalar ko'rinishi ===
yozuvlar list[dict[str, int]]
sarlavha str | None
teglar tuple[str, ...]
return dict[str, list[int]]
Optional[int] ko'rinishi: int | None, int | None bilan bir xil: True
Union[int, str] ko'rinishi: int | str, teng: True
=== 2. get_origin va get_args ===
list[int] origin=list args=(<class 'int'>,)
dict[str, float] origin=dict args=(<class 'str'>, <class 'float'>)
tuple[int, ...] origin=tuple args=(<class 'int'>, Ellipsis)
str | None origin=Union args=(<class 'str'>, <class 'NoneType'>)
collections.abc.Callable[[int, str], bool] origin=Callable args=([<class 'int'>, <class 'str'>], <class 'bool'>)
collections.abc.Sequence[int] origin=Sequence args=(<class 'int'>,)
=== 3. Abstrakt va konkret ===
list Iterable: True Sequence: True ortacha=2.5 uchinchisi=3.0
tuple Iterable: True Sequence: True ortacha=2.5 uchinchisi=3.0
generator Iterable: True Sequence: True ortacha=2.5 uchinchisi=3.0
range Iterable: True Sequence: True ortacha=2.5 uchinchisi=3
=== 4. Callable ===
kvadrat: [1, 4, 9]
abs: [1, 2, 3]
Callable argumentlari: ([<class 'int'>, <class 'str'>], <class 'bool'>)
=== 5. Mapping va o'zgartirish ===
Mapping (faqat o'qish) bilan: ['nok', 'olma']
dict (o'zgartirish) bilan: {'olma': 12000, 'nok': 15000, 'uzum': 21000}
⭐ parametr faqat o'qilsa — Mapping/Sequence/Iterable; o'zgartirilsa — dict/listNima ko'rsatdi: 2.1–2.3-bo'limlar.
Misol 2 — Any, object, Never, None
"""Any va object farqi; toraytirish; Never; -> None; ish vaqtidagi xulq va tekshiruvchi nuqtai nazari."""
import typing
def any_bilan(qiymat: typing.Any) -> int:
"""Tekshiruvchi bu yerda hech narsani tekshirmaydi."""
return qiymat + 1 # tekshiruvchi: OK (lekin ish vaqtida xato bo'lishi mumkin)
def object_bilan(qiymat: object) -> int:
"""Tekshiruvchi: object ustida + ishlatib bo'lmaydi — avval toraytirish kerak."""
if isinstance(qiymat, int):
return qiymat + 1 # ✅ bu yerda qiymat — int
if isinstance(qiymat, str) and qiymat.isdigit():
return int(qiymat) + 1
raise TypeError(f"son kutilgan edi, {type(qiymat).__name__} keldi")
print("=== 1. Any va object ===")
print(f" any_bilan(41) = {any_bilan(41)}")
try:
any_bilan("matn")
except TypeError as xato:
print(f" any_bilan('matn') → TypeError: {xato} ⚠️ tekshiruvchi ogohlantirmagan bo'lardi")
print(f" object_bilan(41) = {object_bilan(41)}, object_bilan('41') = {object_bilan('41')}")
try:
object_bilan([1])
except TypeError as xato:
print(f" object_bilan([1]) → TypeError: {xato} ✅ xato aniq va kutilgan")
print("\n=== 2. Never ===")
def qollab_quvvatlanmaydi(format_nomi: str) -> typing.Never:
raise NotImplementedError(f"{format_nomi} formati qo'llab-quvvatlanmaydi")
def yukla(format_nomi: str) -> list[str]:
if format_nomi == "csv":
return ["a", "b"]
return qollab_quvvatlanmaydi(format_nomi) # tekshiruvchi: bu yo'l qaytmaydi
print(f" yukla('csv') = {yukla('csv')}")
try:
yukla("xml")
except NotImplementedError as xato:
print(f" yukla('xml') → NotImplementedError: {xato}")
print(f" annotatsiya: {typing.get_type_hints(qollab_quvvatlanmaydi)['return']}")
print("\n=== 3. None va -> None ===")
def saqla(yozuv: dict[str, int]) -> None:
yozuv["saqlandi"] = 1
natija = saqla({"a": 1})
print(f" -> None funksiyasi qaytargani: {natija!r}")
print(f" annotatsiyada None turi: {typing.get_type_hints(saqla)['return']}")
print(f" None ning turi: {type(None).__name__}")
print("\n=== 4. Qachon qaysi biri ===")
jadval = [
("Any", "tashqi dinamik ma'lumot, tekshiruvni ataylab o'chirish", "kamdan-kam, izoh bilan"),
("object", "har narsa kelishi mumkin, lekin xavfsiz ishlash kerak", "toraytirish bilan"),
("None", "funksiya qiymat qaytarmaydi", "har doim yozing"),
("Never", "funksiya hech qachon qaytmaydi (raise)", "xato yordamchilarida"),
]
for tur, qachon, tavsiya in jadval:
print(f" {tur:8} {qachon:52} → {tavsiya}")Natijaning muhim qismi:
=== 1. Any va object ===
any_bilan(41) = 42
any_bilan('matn') → TypeError: can only concatenate str (not "int") to str ⚠️ tekshiruvchi ogohlantirmagan bo'lardi
object_bilan(41) = 42, object_bilan('41') = 42
object_bilan([1]) → TypeError: son kutilgan edi, list keldi ✅ xato aniq va kutilgan
=== 2. Never ===
yukla('csv') = ['a', 'b']
yukla('xml') → NotImplementedError: xml formati qo'llab-quvvatlanmaydi
annotatsiya: typing.Never
=== 3. None va -> None ===
-> None funksiyasi qaytargani: None
annotatsiyada None turi: <class 'NoneType'>
None ning turi: NoneType
=== 4. Qachon qaysi biri ===
Any tashqi dinamik ma'lumot, tekshiruvni ataylab o'chirish → kamdan-kam, izoh bilan
object har narsa kelishi mumkin, lekin xavfsiz ishlash kerak → toraytirish bilan
None funksiya qiymat qaytarmaydi → har doim yozing
Never funksiya hech qachon qaytmaydi (raise) → xato yordamchilaridaNima ko'rsatdi: 2.4-bo'lim.
Misol 3 — Turlar taxallusi (PEP 695)
"""type sintaksisi; TypeAliasType va __value__; dangasa hisoblash va rekursiv taxalluslar; generik taxallus; domen tili."""
import typing
type FoydalanuvchiID = int
type Manzil = str
type Ballar = dict[FoydalanuvchiID, list[float]]
type JSON = dict[str, "JSON"] | list["JSON"] | str | int | float | bool | None
type Juft[T] = tuple[T, T]
def ortacha_ball(ballar: Ballar, kim: FoydalanuvchiID) -> float:
qiymatlar = ballar.get(kim, [])
return round(sum(qiymatlar) / len(qiymatlar), 2) if qiymatlar else 0.0
def chegaralar[T](qiymatlar: list[T]) -> Juft[T]:
return qiymatlar[0], qiymatlar[-1]
print("=== 1. Taxallus obyekti ===")
print(f" FoydalanuvchiID turi: {type(FoydalanuvchiID).__name__}, nomi: {FoydalanuvchiID.__name__}")
print(f" __value__: {FoydalanuvchiID.__value__}, ya'ni {FoydalanuvchiID.__value__.__name__}")
print(f" Ballar.__value__: {Ballar.__value__}")
print(f" ⚠️ ish vaqtida FoydalanuvchiID va int bir xil tur: {FoydalanuvchiID.__value__ is int}")
print("\n=== 2. Dangasa hisoblash va rekursiya ===")
print(f" JSON taxallusi rekursiv: {'JSON' in str(JSON.__value__)}")
print(f" hisoblanganda xato bermadi: {type(JSON.__value__).__name__}")
type KeyinAniqlanadi = list[KeyinchalikKlass]
class KeyinchalikKlass:
nom: str
print(f" keyin aniqlanadigan klassga havola: {KeyinAniqlanadi.__value__}")
print("\n=== 3. Generik taxallus ===")
print(f" Juft: {Juft}, tur parametrlari: {Juft.__type_params__}")
print(f" Juft[int]: {Juft[int]}")
print(f" chegaralar([3, 9, 5, 7]) = {chegaralar([3, 9, 5, 7])}")
print(f" chegaralar(['a', 'b', 'c']) = {chegaralar(['a', 'b', 'c'])}")
print("\n=== 4. Imzolarda o'qilishi ===")
print(f" ortacha_ball izohlari: {ortacha_ball.__annotations__}")
print(f" get_type_hints: {typing.get_type_hints(ortacha_ball)}")
ballar: Ballar = {101: [4.5, 5.0, 4.0], 102: [3.0]}
print(f" ortacha_ball(ballar, 101) = {ortacha_ball(ballar, 101)}, yo'q foydalanuvchi: {ortacha_ball(ballar, 999)}")
print("\n=== 5. Domen tili ===")
type Soniya = float
type Millisekund = float
def kutish(vaqt: Soniya) -> Millisekund:
return vaqt * 1000
print(f" kutish(1.5) = {kutish(1.5)}")
print(" ⚠️ taxallus faqat o'qish uchun: ish vaqtida ham, tekshiruvchida ham Soniya va Millisekund — float")
print(" ✅ haqiqiy ajratish kerak bo'lsa — NewType (13.4-dars)")Natijaning muhim qismi:
=== 1. Taxallus obyekti ===
FoydalanuvchiID turi: TypeAliasType, nomi: FoydalanuvchiID
__value__: <class 'int'>, ya'ni int
Ballar.__value__: dict[FoydalanuvchiID, list[float]]
⚠️ ish vaqtida FoydalanuvchiID va int bir xil tur: True
=== 2. Dangasa hisoblash va rekursiya ===
JSON taxallusi rekursiv: True
hisoblanganda xato bermadi: Union
keyin aniqlanadigan klassga havola: list[__main__.KeyinchalikKlass]
=== 3. Generik taxallus ===
Juft: Juft, tur parametrlari: (T,)
Juft[int]: Juft[int]
chegaralar([3, 9, 5, 7]) = (3, 7)
chegaralar(['a', 'b', 'c']) = ('a', 'c')
=== 4. Imzolarda o'qilishi ===
ortacha_ball izohlari: {'ballar': Ballar, 'kim': FoydalanuvchiID, 'return': <class 'float'>}
get_type_hints: {'ballar': Ballar, 'kim': FoydalanuvchiID, 'return': <class 'float'>}
ortacha_ball(ballar, 101) = 4.5, yo'q foydalanuvchi: 0.0
=== 5. Domen tili ===
kutish(1.5) = 1500.0
⚠️ taxallus faqat o'qish uchun: ish vaqtida ham, tekshiruvchida ham Soniya va Millisekund — float
✅ haqiqiy ajratish kerak bo'lsa — NewType (13.4-dars)Nima ko'rsatdi: 2.5-bo'lim.
Misol 4 — Amaliy: "bo'sh" annotatsiyalarni topuvchi
Annotatsiyalar bor, lekin foydasi yo'q holat ko'p uchraydi: Any, parametrsiz list, dict, tuple. Vosita modulni AST bilan tekshirib, shunday joylarni topadi va aniqroq variantni taklif qiladi.
"""AST: Any, parametrsiz konteynerlar, eskirgan typing.List/Optional; tavsiyalar bilan hisobot."""
import ast
PARAMETRSIZ = {"list", "dict", "tuple", "set", "frozenset"}
ESKIRGAN = {"List": "list", "Dict": "dict", "Tuple": "tuple", "Set": "set",
"Optional": "X | None", "Union": "X | Y", "Callable": "collections.abc.Callable"}
class Tekshiruvchi(ast.NodeVisitor):
def __init__(self):
self.topilmalar = []
def izoh_tekshir(self, tugun, joy):
if tugun is None:
self.topilmalar.append((joy[1], joy[0], "annotatsiya yo'q", "turni yozing"))
return
matn = ast.unparse(tugun)
if matn == "Any" or matn.endswith(".Any"):
self.topilmalar.append((joy[1], joy[0], "Any", "aniq tur yoki object + toraytirish"))
elif matn in PARAMETRSIZ:
self.topilmalar.append((joy[1], joy[0], f"parametrsiz {matn}", f"{matn}[...] ko'rinishida yozing"))
else:
asos = matn.split("[")[0].split(".")[-1]
if asos in ESKIRGAN:
self.topilmalar.append((joy[1], joy[0], f"eskirgan {asos}", f"{ESKIRGAN[asos]} ishlating"))
def visit_FunctionDef(self, tugun):
joy = (tugun.name, tugun.lineno)
for a in tugun.args.args + tugun.args.kwonlyargs:
if a.arg not in {"self", "cls"}:
self.izoh_tekshir(a.annotation, (f"{tugun.name}({a.arg})", tugun.lineno))
self.izoh_tekshir(tugun.returns, (f"{tugun.name}() -> ", tugun.lineno))
self.generic_visit(tugun)
visit_AsyncFunctionDef = visit_FunctionDef
MANBA = '''
from typing import Any, Optional, List
def yukla(yol: str) -> dict:
...
def qayta_ishla(yozuvlar: List[dict], sozlama: Optional[dict] = None) -> Any:
...
def xulosa(yozuvlar: list[dict[str, float]], chegara: float = 0.0) -> dict[str, float]:
...
def yubor(manzillar, xabar: str) -> None:
...
class Servis:
def ishga_tushir(self, port: int = 8000) -> None:
...
'''
tekshiruvchi = Tekshiruvchi()
tekshiruvchi.visit(ast.parse(MANBA))
print("=== Annotatsiya sifati hisoboti ===")
print(f" {'qator':>5} {'joy':28} {'muammo':22} tavsiya")
for qator, joy, muammo, tavsiya in sorted(tekshiruvchi.topilmalar):
print(f" {qator:>5} {joy:28} {muammo:22} {tavsiya}")
turlar = {}
for _, _, muammo, _ in tekshiruvchi.topilmalar:
kalit = muammo.split()[0]
turlar[kalit] = turlar.get(kalit, 0) + 1
print(f"\n jami {len(tekshiruvchi.topilmalar)} ta muammo: {dict(sorted(turlar.items()))}")
print(" ⭐ 'xulosa' funksiyasi hisobotga tushmadi — uning annotatsiyalari to'liq va aniq")Natijaning muhim qismi:
=== Annotatsiya sifati hisoboti ===
qator joy muammo tavsiya
4 yukla() -> parametrsiz dict dict[...] ko'rinishida yozing
7 qayta_ishla() -> Any aniq tur yoki object + toraytirish
7 qayta_ishla(sozlama) eskirgan Optional X | None ishlating
7 qayta_ishla(yozuvlar) eskirgan List list ishlating
13 yubor(manzillar) annotatsiya yo'q turni yozing
jami 5 ta muammo: {'Any': 1, 'annotatsiya': 1, 'eskirgan': 2, 'parametrsiz': 1}
⭐ 'xulosa' funksiyasi hisobotga tushmadi — uning annotatsiyalari to'liq va aniqNima ko'rsatdi: 2.1, 2.4, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"typing.List va list — turli narsa" |
Bir xil ma'no; typing.List eskirgan |
"Any — xavfsiz sukut qiymat" |
U tekshiruvni o'chiradi; object xavfsizroq |
"Parametrda list yozish yaxshi" |
Faqat o'qilsa — Iterable/Sequence moslashuvchan |
"dict deb yozsam yetarli" |
dict[str, int] — aniq; parametrsiz dict ma'lumot bermaydi |
| "Taxallus yangi tur yaratadi" | Yo'q — faqat nom; yangi tur uchun NewType |
"-> None ni yozmasa ham bo'ladi" |
Yozilmasa, tekshiruvchi funksiyani tekshirmasligi mumkin |
"Never va None bir xil" |
None — qiymat qaytaradi (None); Never — umuman qaytmaydi |
"reveal_type ni kodda qoldirsa bo'ladi" |
Ish vaqtida stderr ga yozadi — faqat tekshiruv paytida |
6. Keng tarqalgan xatolar va yechimlari
1. Parametrsiz konteyner
def yukla(yol: str) -> dict: # ❌ qanday dict?
def yukla(yol: str) -> dict[str, float]: # ✅2. Parametrda juda tor tur
def ortacha(qiymatlar: list[float]) -> float: # ⚠️ generator bilan ishlamaydi
def ortacha(qiymatlar: Iterable[float]) -> float: # ✅3. Qaytishda juda umumiy tur
def nomlar() -> Iterable[str]: # ⚠️ chaqiruvchi indekslay olmaydi
def nomlar() -> list[str]: # ✅4. Any bilan xatolarni yashirish
def ishla(malumot: Any) -> Any: ... # ❌ tekshiruvchi jim
def ishla(malumot: Yozuv) -> Natija: ... # ✅5. Bo'sh konteynerni annotatsiyasiz qoldirish
ballar = [] # ⚠️ tekshiruvchi: list[Unknown]
ballar: list[int] = [] # ✅6. str ni Iterable[str] sifatida qabul qilish
def yubor(manzillar: Iterable[str]) -> None: # ⚠️ str ham mos keladi (13.1-dars xatosi)
def yubor(manzillar: Sequence[str]) -> None: # ⚠️ str yana mos!
def yubor(manzillar: list[str]) -> None: # ✅ eng aniq7. Eskirgan importlar
from typing import List, Optional # ⚠️ yangi kodda kerak emas8. Callable ni murakkab imzolar uchun ishlatish
ishlov: Callable[..., None] # ⚠️ argumentlar yo'qoldi
class Ishlov(Protocol): # ✅ 13.5-dars
def __call__(self, xabar: str, *, qayta: int = 0) -> None: ...7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 6-qism (o'tilgan): ma'lumot tuzilmalari —
Sequence,Mappingprotokollari - 10.1–10.2-darslar (o'tilgan): iterator va iterable —
Iterableturi shundan - 13.1-dars (o'tilgan): annotatsiyalar nima
- 13.3-dars:
Optional,Union,Literalva toraytirish - 13.4-dars: generiklar,
TypeVar,NewType,ParamSpec - 13.5–13.6-darslar:
Protocol,TypedDict - 15-qism: standart kutubxona imzolarini o'qish
- 20-qism: FastAPI — annotatsiyalardan API hujjati
8. Eng yaxshi amaliyotlar
Zamonaviy sintaksis:
list[int],str | None,type Nom = ....Parametrda umumiy, qaytishda aniq tur.
Anyo'rnigaobject+ toraytirish.Bo'sh konteynerlarni annotatsiyalang.
Murakkab tuzilmalarga taxallus bering — imzolar qisqaradi.
Neverbilan "qaytmaydigan" funksiyalarni belgilang.reveal_typeni faqat tekshiruv paytida ishlating.Annotatsiya sifatini avtomatik tekshiring (Misol 4) va CI ga qo'shing.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
import typing
from collections.abc import Iterable, Sequence
1. print(typing.get_origin(list[int]))
2. print(typing.get_args(dict[str, int]))
3. print(typing.Optional[int] == (int | None))
4. print(typing.get_args(int | str | None))
5. type Yol = str
print(type(Yol).__name__)
6. print(Yol.__value__)
7. type Juft[T] = tuple[T, T]
print(Juft.__type_params__)
8. print(isinstance("abc", Iterable), isinstance("abc", Sequence))
9. print(isinstance((1, 2), Sequence), isinstance({1, 2}, Sequence))
10. def f() -> None:
pass
print(f() is None, typing.get_type_hints(f))
11. print(typing.get_origin(Sequence[int]).__name__)
12. x: list[int] = [1, 2]
print(typing.assert_type(x, list[int]) == x)Javoblar
<class 'list'>(<class 'str'>, <class 'int'>)True(<class 'int'>, <class 'str'>, <class 'NoneType'>)TypeAliasType<class 'str'>(T,)True True— satr ham ketma-ketlikTrue False— to'plam indekslanmaydiTrue {'return': <class 'NoneType'>}SequenceTrue—assert_typeqiymatni o'zgarishsiz qaytaradi
Vazifa 2: Xatolarni tuzating
1. from typing import List, Dict, Optional
def guruhla(yozuvlar: List[Dict], kalit: str) -> Optional[Dict]:
...
2. def ortacha(qiymatlar: list[float]) -> float:
return sum(qiymatlar) / len(qiymatlar) # generator bilan ham ishlatiladi
3. def sozlama_yukla(yol: str) -> dict:
...
4. def qayta_ishla(malumot: typing.Any) -> typing.Any:
return malumot["natija"] * 2
5. natijalar = []
def qosh(x: int) -> None:
natijalar.append(x)Javoblar
1. def guruhla(yozuvlar: list[dict[str, int]], kalit: str) -> dict[str, list[int]] | None:
...
2. from collections.abc import Iterable
def ortacha(qiymatlar: Iterable[float]) -> float:
royxat = list(qiymatlar) # generatorni bir marta o'qiymiz
return sum(royxat) / len(royxat)
3. def sozlama_yukla(yol: str) -> dict[str, str | int | bool]:
...
# yoki aniqroq: TypedDict (13.6-dars)
4. def qayta_ishla(malumot: dict[str, int]) -> int:
return malumot["natija"] * 2
5. natijalar: list[int] = [] # bo'sh konteyner annotatsiyalanadi
def qosh(x: int) -> None:
natijalar.append(x)Vazifa 3: Kutubxona imzolarini yozish
Quyidagi funksiyalar uchun to'liq annotatsiya yozing va nima uchun shunday tanlaganingizni izohlang:
guruhla(yozuvlar, kalit_funksiya)— elementlarni kalit bo'yicha guruhlaydibirinchi_mos(elementlar, shart, sukut=None)— shartga mos birinchi elementqayta_urin(funksiya, urinishlar=3, kutish=1.0)— funksiyani qayta chaqiradioqim_oqi(fayl, bolak_hajmi=8192)— bo'laklab o'qiydixarita_birlashtir(*xaritalar)— bir nechta lug'atni birlashtiradi
Vazifa 4: Taxalluslar lug'ati
O'z loyihangiz (yoki o'quv loyihasi) uchun domen taxalluslari to'plamini yarating:
- Kamida 8 ta taxallus: identifikatorlar, vaqt birliklari, pul, JSON tuzilmalari
- Ularni
turlar.pymoduliga joylang va imzolarda ishlating - Rekursiv taxallus (
JSON) yozing va uni ishlatib ko'ring NewTypebilan taqqoslang: qaysi hollarda taxallus yetarli emas (13.4-darsga tayyorgarlik)
Vazifa 5: Annotatsiya sifati vositasi
Misol 4 ni rivojlantiring:
- Sinf atributlari va modul darajasidagi o'zgaruvchilarni ham tekshirsin
# type: ignoreva# noqaizohlarini hurmat qilsin- Muammo darajalarini joriy qiling: xato (
Any), ogohlantirish (parametrsiz konteyner), maslahat (eskirgan import) - JSON hisobot va CI uchun chiqish kodi qo'shing
- O'z loyihangizga qo'llab, birinchi 20 muammoni tuzating
Vazifa 6: Abstraktdan konkretga
Bitta funksiyaning to'rt variantini yozing: list, Sequence, Iterable, Iterator parametri bilan:
- Har biri qanday manbalar bilan ishlashini jadvalda ko'rsating (ro'yxat, kortej, generator,
range, fayl obyekti) - Qaysi variantda ikki marta aylanib chiqish mumkinligini ko'rsating
- Generatorni ikki marta aylanishga urinib, natijani tushuntiring
- Har variant uchun mos real vaziyat keltiring
Vazifa 7: O'ylash
TypeScript'da any va unknown bor — unknown bilan ishlash uchun turni toraytirish shart; Java'da Object va generiklar tur o'chirish (type erasure) bilan; Go'da any (interface{}) va turlar tasdiqlash (type assertion). Python'dagi Any va object shu vositalarga qanday mos keladi, va nega Any "yuqumli" (viral) deb ataladi?
Javob
Qisqa javob: Any — TypeScript'dagi any ning aynan o'zi: u bilan har qanday amal ruxsat etiladi va natija ham Any bo'ladi, shuning uchun tekshiruv "o'chgan zona" kod bo'ylab tarqaladi. object esa TypeScript'dagi unknown ga o'xshaydi: qiymat bor, lekin uni ishlatish uchun avval turni toraytirish kerak.
1. Taqqoslash
| Python | TypeScript | Java | Go | Ma'nosi |
|---|---|---|---|---|
Any |
any |
(yo'q) | interface{} + tekshiruvsiz |
Tekshiruvni o'chirish |
object |
unknown |
Object |
any + type assertion |
Har narsa, lekin avval toraytirish |
isinstance bilan toraytirish |
typeof, instanceof |
instanceof + cast |
type switch | Turni aniqlash |
Never |
never |
(yo'q) | (yo'q) | Qaytmaydigan yo'l |
2. Nega Any yuqumli
def yukla(yol: str) -> Any: ...
malumot = yukla("a.json") # malumot: Any
soni = malumot["yozuvlar"] # soni: Any ← tekshiruv yo'q
jami = soni + 1 # jami: Any ← xato bo'lsa ham jimHar amal natijasi yana Any bo'lgani uchun "o'chgan zona" butun quvur bo'ylab tarqaladi. Bir nechta Any katta loyihada tekshiruvni amalda foydasiz qilishi mumkin — mypy da --disallow-any-expr, warn_return_any kabi bayroqlar shuning uchun bor (13.7-dars).
3. object bilan ishlash
def chop(qiymat: object) -> str:
if isinstance(qiymat, str):
return qiymat.upper() # bu yerda str
if isinstance(qiymat, (int, float)):
return f"{qiymat:.2f}"
return repr(qiymat) # object da ham repr borToraytirish (narrowing) — tekshiruvchi isinstance, is None, assert, match kabi konstruksiyalarni tushunadi (13.3-dars).
4. Java va Go tajribasi
- Java'da generiklar tur o'chirish bilan: ish vaqtida
List<String>hamList— Python'ga o'xshash (annotatsiyalar ish vaqtida majburlamaydi) - Go'da
interface{}(hozirany) uzoq vaqt yagona yo'l edi; generiklar 1.18 da qo'shildi — "turlarsiz moslashuvchanlik" narxi hammaga tanish - Ikkala tilda ham amaliyot bir xil: umumiy turdan foydalanishdan oldin aniq tekshiruv
5. Amaliy qoidalar
Anyni faqat chegarada va izoh bilan ishlating (# tashqi kutubxona imzosi yo'q)- Ichkariga
Anytarqalmasin: chegarada aniq turga o'giring (pydantic, qo'lda tekshiruv) - "Nima kelishini bilmayman" holatida
object— tekshiruvchi sizni toraytirishga majburlaydi mypy --strictdaAnyqaytaruvchi funksiyalar ogohlantiriladi — buni yoqing
Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.
Xulosa
Bu darsda typing ning kundalik asoslarini o'rgandik.
Eng muhim uch fikr:
Zamonaviy sintaksis sodda.
list[int],dict[str, float],tuple[int, ...],str | None—typing.ListvaOptionalyangi kodda kerak emas. ParametrlardaIterable,Sequence,Mappingkabi abstrakt turlar moslashuvchanlik beradi, qaytishda esa aniqlist/dictchaqiruvchiga ko'proq imkon beradi. Funksiyalar uchunCallable[[int], str], murakkab imzolar uchunProtocol.Any— tekshiruvni o'chiradi,object— xavfsiz.Anybilan har qanday amal ruxsat etiladi va natija yanaAnybo'lib tarqaladi;objectesa turni toraytirishga majbur qiladi.-> None— qiymat qaytarmaydigan funksiya,-> Never— umuman qaytmaydigan (raise) funksiya.Taxalluslar domen tilini beradi.
type Ballar = dict[int, list[float]]uzun imzolarni qisqartiradi,typesintaksisi (PEP 695) dangasa hisoblanadi — rekursiv va oldinga havolalar tabiiy ishlaydi,X.__value__asl turni ko'rsatadi. Lekin taxallus yangi tur yaratmaydi:SoniyavaMillisekundbaribirfloat— haqiqiy ajratish uchunNewTypekerak.
Keyingi darsda ixtiyoriy qiymatlar va variantlar bilan ishlaymiz: str | None, birlashmalar, Literal, Enum bilan solishtirish va eng muhimi — turni toraytirish (narrowing) qoidalari.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!