Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Docstring asoslari
- 2.2. Docstring formatlari
- 2.3. Tur ko'rsatkichlari — asoslar
- 2.4. Murakkab turlar
- 2.5. mypy — statik tekshiruv
- 2.6. doctest
- 2.7. Qachon tur ko'rsatkichi kerak
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Docstring
- Misol 2 — Tur ko'rsatkichlari
- Misol 3 — mypy va doctest
- Misol 4 — Amaliy: to'liq hujjatlangan modul
- 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
- 7-QISM YAKUNI
7.14-dars: Docstring va tur ko'rsatkichlari
7-QISM — FUNKSIYALAR · 14-dars · 7-QISM YAKUNI
1. Kirish va motivatsiya
Ikki funksiya, bir xil mantiq:
def f(a, b, c=None):
if c is None:
c = []
return [x for x in a if x > b] + cdef filtrla_va_qosh(
sonlar: list[int],
chegara: int,
qoshimcha: list[int] | None = None,
) -> list[int]:
"""Chegaradan katta sonlarni ajratib, qo'shimchani ulaydi.
Argumentlar:
sonlar: Filtrlanadigan sonlar ro'yxati.
chegara: Bu qiymatdan KATTA sonlar qoladi.
qoshimcha: Oxiriga qo'shiladigan ro'yxat (None — bo'sh).
Qaytaradi:
Filtrlangan sonlar + qo'shimcha.
Misol:
>>> filtrla_va_qosh([1, 5, 3], 2)
[5, 3]
>>> filtrla_va_qosh([1, 5], 0, [9])
[1, 5, 9]
"""
qoshimcha = [] if qoshimcha is None else qoshimcha
return [x for x in sonlar if x > chegara] + qoshimchaIkkinchisi uzunroq, lekin:
- IDE avtoto'ldirish beradi
mypyxatolarni yozish paytida topadihelp()foydali>>>misollari test sifatida ishlaydi (doctest)- Olti oydan keyin siz ham tushunasiz
Bu darsda:
- Docstring formatlari va PEP 257
- Tur ko'rsatkichlari — sintaksis va zamonaviy uslub
mypy— statik tekshiruvOptional,Union,Callable,TypeVar,Protocoldoctest— hujjatdagi testlar- Qachon tur ko'rsatkichi kerak, qachon ortiqcha
2. Nazariya — chuqur tushuntirish
2.1. Docstring asoslari
Docstring — funksiya, sinf yoki modulning birinchi buyrug'i bo'lgan satr:
def f():
"""Bu — docstring."""
...
f.__doc__ # 'Bu — docstring.'
help(f) # docstringni ko'rsatadiFaqat birinchi buyruq:
def f():
x = 1
"""Bu docstring EMAS.""" # oddiy satr ifodasi
f.__doc__ # NonePEP 257 qoidalari:
def qisqa():
"""Bir qatorli — nuqta bilan tugaydi."""
def uzun():
"""Qisqa xulosa (bir qator, imperativ).
Batafsil tushuntirish. Bo'sh qator bilan ajratilgan.
Bir necha qator bo'lishi mumkin.
"""Qoidalar:
- Uch qo'shtirnoq (
"""), hatto bir qatorli bo'lsa ham - Birinchi qator — qisqa xulosa, nuqta bilan
- Ko'p qatorli bo'lsa — xulosadan keyin bo'sh qator
- Yopuvchi
"""alohida qatorda - Imperativ shakl: "Qaytaradi", "Hisoblaydi" — "Qaytaradigan" emas
Nima yozmaslik kerak:
def yigindi(a, b):
"""a va b ni qo'shadi.""" # ⚠️ kod aytadi
return a + b
def yigindi(a: int, b: int) -> int:
"""Ikki sonning yig'indisini qaytaradi.
Toshib ketishni tekshirmaydi — Python int cheksiz.
"""
return a + b # ✅ NIMA UCHUN va NOZIKLIKDocstring nima uchun va noziklikni tushuntiradi, nima qilishini emas — buni kod aytadi.
2.2. Docstring formatlari
Uch asosiy format:
1. Google uslubi (eng o'qiladigan):
def bol(a: float, b: float) -> float:
"""Ikki sonni bo'ladi.
Args:
a: Bo'linuvchi.
b: Bo'luvchi (nol bo'lmasligi kerak).
Returns:
Bo'linma natijasi.
Raises:
ZeroDivisionError: b nol bo'lsa.
Example:
>>> bol(10, 2)
5.0
"""2. NumPy uslubi (ilmiy kutubxonalarda):
def bol(a, b):
"""Ikki sonni bo'ladi.
Parameters
----------
a : float
Bo'linuvchi.
b : float
Bo'luvchi.
Returns
-------
float
Bo'linma.
Raises
------
ZeroDivisionError
b nol bo'lsa.
"""3. reST / Sphinx (eski, :param: bilan):
def bol(a, b):
"""Ikki sonni bo'ladi.
:param a: Bo'linuvchi.
:param b: Bo'luvchi.
:returns: Bo'linma.
:raises ZeroDivisionError: b nol bo'lsa.
"""Tavsiya: loyihada bitta format tanlang. Google uslubi eng ko'p ishlatiladi.
O'zbekcha loyihada:
def bol(a: float, b: float) -> float:
"""Ikki sonni bo'ladi.
Argumentlar:
a: Bo'linuvchi.
b: Bo'luvchi (nol bo'lmasligi kerak).
Qaytaradi:
Bo'linma natijasi.
Xatolar:
ZeroDivisionError: b nol bo'lsa.
"""Vositalar (sphinx, pdoc) ingliz kalit so'zlarini kutadi, lekin ichki hujjat uchun o'zbekcha ham mumkin.
2.3. Tur ko'rsatkichlari — asoslar
def f(a: int, b: str = "x", *args: float, c: bool = True,
**kwargs: object) -> list[int]:
...Python ularni TEKSHIRMAYDI:
def f(x: int) -> str:
return x * 2
f("abc") # ✅ ishlaydi, "abcabc" qaytaradiTur ko'rsatkichi — hujjat va statik tahlil uchun.
__annotations__ da saqlanadi:
f.__annotations__ # {'x': <class 'int'>, 'return': <class 'str'>}Asosiy turlar:
int, float, str, bool, bytes, None
list[int] # 3.9+
dict[str, int]
tuple[int, str] # aniq ikkita
tuple[int, ...] # cheksiz
set[str], frozenset[int]Eski sintaksis (3.9 gacha):
from typing import List, Dict, Tuple, Set
def f(r: List[int]) -> Dict[str, int]: ... # ⚠️ eskirgan
def f(r: list[int]) -> dict[str, int]: ... # ✅ 3.9+Ixtiyoriy va birlashma:
# Zamonaviy (3.10+)
def f(x: int | None) -> str | bytes: ...
# Eski
from typing import Optional, Union
def f(x: Optional[int]) -> Union[str, bytes]: ... X | None — Optional[X] bilan bir xil.
Sukut qiymat None bo'lsa:
def f(x: int = None): ... # ⚠️ mypy: xato
def f(x: int | None = None): ... # ✅2.4. Murakkab turlar
Funksiyalar:
from typing import Callable
def qoll(f: Callable[[int, int], int], a: int, b: int) -> int:
return f(a, b)
# Argumentlar noma'lum
f: Callable[..., int]Iterable va boshqalar:
from collections.abc import (Iterable, Iterator, Sequence, Mapping,
Callable, Generator)
def f(r: Iterable[int]) -> Iterator[str]: ...
def g(d: Mapping[str, int]) -> None: ... # o'qish uchun
def h(s: Sequence[int]) -> int: ... # indeks kerakArgument uchun eng umumiy tur, qaytarish uchun eng aniq:
def f(r: Iterable[int]) -> list[int]: # ✅
return sorted(r)
def f(r: list[int]) -> Iterable[int]: # ⚠️ teskariTypeVar — generiklar:
from typing import TypeVar
T = TypeVar("T")
def birinchi(r: list[T]) -> T:
return r[0]
birinchi([1, 2]) # int deb aniqlanadi
birinchi(["a"]) # strChegara bilan:
Son = TypeVar("Son", int, float)
def qosh(a: Son, b: Son) -> Son:
return a + bProtocol — "duck typing" turi:
from typing import Protocol
class Uzunlikli(Protocol):
def __len__(self) -> int: ...
def hajm(x: Uzunlikli) -> int:
return len(x)
hajm([1, 2]) # ✅ list — __len__ bor
hajm("abc") # ✅
hajm(42) # ❌ mypy xato Protocol — meros talab qilmaydi. Bu — Pythonning duck typing falsafasiga mos.
Boshqa foydali turlar:
from typing import Any, Never, Literal, Final, TypeAlias
x: Any # har qanday (tekshiruv o'chadi)
def f() -> Never: raise ... # hech qachon qaytmaydi (3.11+)
def f(rejim: Literal["r", "w"]): ...
MAKSIMAL: Final = 100 # qayta o'zlashtirmang
Yol: TypeAlias = str | Path # taxallusDekoratorlar (ParamSpec, 3.10+):
from typing import ParamSpec, TypeVar
from collections.abc import Callable
from functools import wraps
P = ParamSpec("P")
R = TypeVar("R")
def jurnal(f: Callable[P, R]) -> Callable[P, R]:
@wraps(f)
def ichki(*args: P.args, **kwargs: P.kwargs) -> R:
return f(*args, **kwargs)
return ichkiBu — dekoratordan keyin imzo saqlanadi.
2.5. mypy — statik tekshiruv
pip install mypy
mypy fayl.pydef f(x: int) -> str:
return x * 2 # error: Incompatible return value type
# (got "int", expected "str")Foydali bayroqlar:
mypy --strict fayl.py # eng qat'iy
mypy --disallow-untyped-defs # har funksiyada tur bo'lsin
mypy --warn-return-any # Any qaytarishni ogohlantir
mypy --check-untyped-defs # tursiz funksiyalarni ham tekshirpyproject.toml da:
[tool.mypy]
python_version = "3.12"
strict = true
warn_unused_ignores = trueXatoni o'chirish:
x = f() # type: ignore
x = f() # type: ignore[arg-type] # ✅ aniq kod bilanMuqobil vositalar:
| Vosita | Xususiyat |
|---|---|
mypy |
Eng keng tarqalgan, Python jamoasi |
pyright / Pylance |
Tez, VS Code ichida |
pyre |
Meta, katta kod bazalari uchun |
pytype |
Google, tur ko'rsatkichisiz ham ishlaydi |
Ish vaqtida tekshirish:
# pydantic
from pydantic import BaseModel
class Foydalanuvchi(BaseModel):
ism: str
yosh: int
Foydalanuvchi(ism="Aziz", yosh="30") # ✅ "30" → 30 aylantiriladi
Foydalanuvchi(ism="Aziz", yosh="abc") # ❌ ValidationErrorbeartype, typeguard — dekorator bilan tekshirish.
2.6. doctest
Docstring ichidagi >>> misollari — bajariladigan testlar:
def kvadrat(x: int) -> int:
"""Sonning kvadratini qaytaradi.
>>> kvadrat(5)
25
>>> kvadrat(-3)
9
>>> kvadrat(0)
0
"""
return x ** 2python -m doctest fayl.py -vimport doctest
doctest.testmod()Foydasi:
- Misollar eskirmaydi (test buziladi)
- Hujjat va test — bir joyda
help()da foydali misollar
Cheklovlar:
>>> {"b": 1, "a": 2} # ✅ dict tartibi barqaror
{'b': 1, 'a': 2}
>>> {1, 2, 3} # ⚠️ set tartibi nomustaqil
{1, 2, 3}
>>> f() # ⚠️ float aniqligi
0.30000000000000004Yechimlar:
>>> sorted({3, 1, 2})
[1, 2, 3]
>>> round(f(), 2)
0.3
>>> f() # doctest: +ELLIPSIS
0.30000...
>>> f() # doctest: +SKIPQachon doctest:
- Sodda, aniq misollar
- Hujjat sifatida qimmatli
- Murakkab sozlash kerak (
pytestishlating) - Ko'p test holati
2.7. Qachon tur ko'rsatkichi kerak
Doim:
- Ommaviy API (kutubxona, modul chegarasi)
- Murakkab imzolar
- Jamoa loyihasi
- Uzoq muddatli kod
Ixtiyoriy:
- Kichik skript
- Prototip
- Ravshan ichki funksiyalar
Ortiqcha:
def f(x: int) -> int:
return x + 1 # ravshan, lekin zarar ham yo'q
for i: int in range(10): ... # ❌ sintaksis yo'qBosqichma-bosqich qo'shish:
mypy --check-untyped-defs # avval mavjud kodni tekshiring
# keyin funksiyalarga tur qo'shing
mypy --disallow-untyped-defs # oxirida majburiy qilingFoydasi raqamlarda:
Dropbox (4 million qator Python) tur ko'rsatkichlariga o'tgach:
- Refaktoring xavfsizroq
- IDE yordami sezilarli yaxshilandi
- Ish vaqtidagi
TypeErrorlar kamaydi
Lekin: tur ko'rsatkichi test o'rnini bosmaydi.
3. Tez ma'lumotnoma
Docstring (PEP 257)
def f():
"""Bir qatorli — nuqta bilan."""
def g():
"""Qisqa xulosa.
Batafsil tushuntirish.
"""Uch qo'shtirnoq DOIM
Birinchi qator — qisqa, imperativ, nuqta bilan
Ko'p qatorli → xulosadan keyin bo'sh qator
NIMA UCHUN va NOZIKLIK yozing, NIMA QILISHINI emasGoogle formati
"""Qisqa xulosa.
Args:
a: Izoh.
b: Izoh.
Returns:
Nima qaytaradi.
Raises:
ValueError: Qachon.
Example:
>>> f(1)
2
"""Tur ko'rsatkichlari
def f(a: int, b: str = "x", *args: float,
c: bool = True, **kw: object) -> list[int]: ...
list[int], dict[str, int], tuple[int, ...] 3.9+
int | None 3.10+ (Optional o'rniga)
Callable[[int, int], int]
Iterable / Iterator / Sequence / Mapping collections.abc
TypeVar("T") generik
Protocol duck typing
Literal["r", "w"], Final, Any, Never
ParamSpec dekoratorlar (3.10+)
⚠️ Python TEKSHIRMAYDI — mypy kerak
⭐ Argument: umumiy tur. Qaytarish: aniq tur.mypy
mypy fayl.py
mypy --strict
mypy --disallow-untyped-defs
# type: ignore[kod]doctest
"""
>>> f(5)
25
"""
python -m doctest fayl.py -v
⚠️ set tartibi, float aniqligi → sorted(), round(), +ELLIPSIS4. Batafsil misollar
Misol 1 — Docstring
"""Docstring formatlari va qoidalari."""
import inspect
import textwrap
print("=== 1. Asosiy qoidalar ===")
def bir_qatorli():
"""Bir qatorli docstring — nuqta bilan tugaydi."""
def kop_qatorli():
"""Qisqa xulosa bir qatorda.
Batafsil tushuntirish shu yerda. U bir necha
qatordan iborat bo'lishi mumkin.
Yopuvchi qo'shtirnoq alohida qatorda.
"""
def docstringsiz():
pass
def notogri():
x = 1
"""Bu docstring EMAS — birinchi buyruq emas."""
return x
print(f" {'Funksiya':<18} {'__doc__ bormi':<16} {'Birinchi qator'}")
print(" " + "─" * 66)
for f in [bir_qatorli, kop_qatorli, docstringsiz, notogri]:
doc = f.__doc__
bor = "✅" if doc else "❌"
birinchi = doc.splitlines()[0] if doc else "—"
print(f" {f.__name__:<18} {bor:<16} {birinchi[:34]}")
print(f"\n ⚠️ Docstring FAQAT birinchi buyruq bo'lishi kerak")
print("\n=== 2. inspect.getdoc — tozalangan ===")
print(f" __doc__ (xom):")
print(f" {kop_qatorli.__doc__!r}\n")
print(f" inspect.getdoc (otstup tozalangan):")
for q in inspect.getdoc(kop_qatorli).splitlines():
print(f" {q!r}")
print(f"\n ⭐ inspect.getdoc:")
print(f" • Umumiy otstupni olib tashlaydi")
print(f" • Boshi va oxiridagi bo'sh qatorlarni tozalaydi")
print(f" • Meros bo'lgan docstringni ham topadi")
print("\n=== 3. Uch format ===")
def google_uslubi(a: float, b: float) -> float:
"""Ikki sonni bo'ladi.
Args:
a: Bo'linuvchi.
b: Bo'luvchi (nol bo'lmasligi kerak).
Returns:
Bo'linma natijasi.
Raises:
ZeroDivisionError: b nol bo'lsa.
Example:
>>> google_uslubi(10, 2)
5.0
"""
return a / b
def numpy_uslubi(a, b):
"""Ikki sonni bo'ladi.
Parameters
----------
a : float
Bo'linuvchi.
b : float
Bo'luvchi.
Returns
-------
float
Bo'linma.
Raises
------
ZeroDivisionError
b nol bo'lsa.
"""
return a / b
def rest_uslubi(a, b):
"""Ikki sonni bo'ladi.
:param a: Bo'linuvchi.
:type a: float
:param b: Bo'luvchi.
:type b: float
:returns: Bo'linma.
:rtype: float
:raises ZeroDivisionError: b nol bo'lsa.
"""
return a / b
def ozbekcha_uslubi(a: float, b: float) -> float:
"""Ikki sonni bo'ladi.
Argumentlar:
a: Bo'linuvchi.
b: Bo'luvchi (nol bo'lmasligi kerak).
Qaytaradi:
Bo'linma natijasi.
Xatolar:
ZeroDivisionError: b nol bo'lsa.
"""
return a / b
FORMATLAR = [
("Google", google_uslubi, "Eng o'qiladigan, keng tarqalgan"),
("NumPy", numpy_uslubi, "Ilmiy kutubxonalarda"),
("reST/Sphinx", rest_uslubi, "Eski, Sphinx uchun"),
("O'zbekcha", ozbekcha_uslubi, "Ichki loyihalar uchun"),
]
for nom, f, izoh in FORMATLAR:
print(f"\n {nom} ({izoh}):")
qatorlar = inspect.getdoc(f).splitlines()
for q in qatorlar[:8]:
print(f" {q}")
if len(qatorlar) > 8:
print(f" ...")
print("\n\n=== 4. ⚠️ Nima yozmaslik kerak ===")
print(""" ❌ Kod aytadigan narsani takrorlash:
def yigindi(a, b):
\"\"\"a va b ni qo'shadi.\"\"\"
return a + b
✅ NIMA UCHUN va NOZIKLIK:
def yigindi(a: int, b: int) -> int:
\"\"\"Ikki butun sonning yig'indisi.
Toshib ketishni tekshirmaydi — Python int cheksiz.
Float bilan aniqlik yo'qolishi mumkin.
\"\"\"
return a + b
❌ Ortiqcha:
def get_name(self):
\"\"\"Getter for name.\"\"\" # ravshan
return self._name
✅ Nozik holat bor bo'lsa:
def get_name(self):
\"\"\"Ism. Agar o'rnatilmagan bo'lsa — bo'sh satr.\"\"\"
return self._name or ""
""")
print("=== 5. Amaliy: to'liq docstring ===")
def qidir(
matn: str,
naqsh: str,
*,
katta_kichik: bool = False,
butun_soz: bool = False,
chegara: int | None = None,
) -> list[tuple[int, str]]:
"""Matnda naqsh bo'yicha qidiradi.
Qidiruv qatorma-qator amalga oshiriladi. Har mos qator uchun
(qator_raqami, qator_matni) juftligi qaytariladi.
Argumentlar:
matn: Qidiriladigan matn (ko'p qatorli bo'lishi mumkin).
naqsh: Qidirilayotgan matn (oddiy satr, regex emas).
katta_kichik: True bo'lsa katta-kichik harf farqlanadi.
butun_soz: True bo'lsa faqat butun so'z mos keladi.
chegara: Maksimal natijalar soni (None — cheklovsiz).
Qaytaradi:
(qator_raqami, qator) juftliklari ro'yxati.
Qator raqamlari 1 dan boshlanadi.
Xatolar:
ValueError: naqsh bo'sh bo'lsa.
Misol:
>>> matn = "Salom dunyo\\nSalom Python"
>>> qidir(matn, "salom")
[(1, 'Salom dunyo'), (2, 'Salom Python')]
>>> qidir(matn, "salom", katta_kichik=True)
[]
>>> qidir(matn, "Salom", chegara=1)
[(1, 'Salom dunyo')]
Eslatma:
Katta matnlar uchun generator versiyasi — `qidir_oqim`.
"""
if not naqsh:
raise ValueError("naqsh bo'sh bo'lmasligi kerak")
natija = []
qidirilayotgan = naqsh if katta_kichik else naqsh.casefold()
for i, qator in enumerate(matn.splitlines(), 1):
tekshiriladigan = qator if katta_kichik else qator.casefold()
if butun_soz:
mos = qidirilayotgan in tekshiriladigan.split()
else:
mos = qidirilayotgan in tekshiriladigan
if mos:
natija.append((i, qator))
if chegara and len(natija) >= chegara:
break
return natija
print(f" Docstring bo'limlari:\n")
doc = inspect.getdoc(qidir)
bolimlar = []
joriy = None
for q in doc.splitlines():
if q and not q.startswith(" ") and q.endswith(":"):
joriy = q.rstrip(":")
bolimlar.append(joriy)
print(f" {bolimlar}")
print(f"\n help(qidir) chiqishining boshi:\n")
for q in doc.splitlines()[:12]:
print(f" {q}")
print(f" ...")
print(f"\n Sinov:")
MATN = "Salom dunyo\nSalom Python\nXayr dunyo"
SINOVLAR = [
("qidir(m, 'salom')", {"naqsh": "salom"}),
("qidir(m, 'salom', katta_kichik=True)",
{"naqsh": "salom", "katta_kichik": True}),
("qidir(m, 'dunyo')", {"naqsh": "dunyo"}),
("qidir(m, 'dunyo', chegara=1)", {"naqsh": "dunyo", "chegara": 1}),
]
for kod, kwargs in SINOVLAR:
natija = qidir(MATN, **kwargs)
print(f" {kod:<40} → {natija}")
print("\n=== 6. Docstring statistikasi ===")
def docstring_tahlil(f) -> dict:
doc = inspect.getdoc(f)
if not doc:
return {"bor": False}
qatorlar = doc.splitlines()
bolimlar = [q.rstrip(":") for q in qatorlar
if q and not q.startswith(" ") and q.endswith(":")]
misollar = sum(1 for q in qatorlar if q.strip().startswith(">>>"))
sig = inspect.signature(f)
hujjatlangan = sum(
1 for p in sig.parameters
if any(q.strip().startswith(f"{p}:") for q in qatorlar)
)
return {
"bor": True,
"qatorlar": len(qatorlar),
"bolimlar": bolimlar,
"misollar": misollar,
"parametrlar": len(sig.parameters),
"hujjatlangan": hujjatlangan,
}
FUNKSIYALAR = [qidir, google_uslubi, bir_qatorli, docstringsiz]
print(f" {'Funksiya':<18} {'Qator':>6} {'Misol':>6} {'Param':>7} {'Hujjat':>8}")
print(" " + "─" * 52)
for f in FUNKSIYALAR:
t = docstring_tahlil(f)
if not t["bor"]:
print(f" {f.__name__:<18} {'—':>6} {'—':>6} {'—':>7} {'❌':>8}")
continue
foiz = (f"{t['hujjatlangan']}/{t['parametrlar']}"
if t["parametrlar"] else "—")
print(f" {f.__name__:<18} {t['qatorlar']:>6} {t['misollar']:>6} "
f"{t['parametrlar']:>7} {foiz:>8}")Natijaning muhim qismi:
=== 1. Asosiy qoidalar ===
Funksiya __doc__ bormi Birinchi qator
──────────────────────────────────────────────────────────────────
bir_qatorli ✅ Bir qatorli docstring — nuqta
kop_qatorli ✅ Qisqa xulosa bir qatorda.
docstringsiz ❌ —
notogri ❌ —
=== 5. Amaliy: to'liq docstring ===
Docstring bo'limlari:
['Argumentlar', 'Qaytaradi', 'Xatolar', 'Misol', 'Eslatma']
Sinov:
qidir(m, 'salom') → [(1, 'Salom dunyo'), (2, ...)]
qidir(m, 'salom', katta_kichik=True) → []
qidir(m, 'dunyo', chegara=1) → [(1, 'Salom dunyo')]Nima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — Tur ko'rsatkichlari
"""Tur ko'rsatkichlarining barcha shakllari."""
import inspect
from collections.abc import Callable, Iterable, Iterator, Sequence, Mapping
from typing import (Any, Final, Literal, Protocol, TypeVar,
TypeAlias, overload)
from dataclasses import dataclass
print("=== 1. Asosiy turlar ===")
def asosiy(
a: int,
b: str,
c: float,
d: bool,
e: bytes,
f: None,
) -> tuple[int, str]:
return a, b
print(f" __annotations__:")
for nom, tur in asosiy.__annotations__.items():
tur_nomi = getattr(tur, "__name__", str(tur))
print(f" {nom:<10} {tur_nomi}")
print(f"\n ⚠️ Python TEKSHIRMAYDI:")
def kvadrat(x: int) -> int:
return x * 2
SINOVLAR = [5, 2.5, "ab", [1, 2], True]
for x in SINOVLAR:
try:
natija = f"✅ {kvadrat(x)!r}"
except TypeError as e:
natija = f"❌ {e}"
print(f" kvadrat({x!r:<8}) → {natija}")
print(f"\n ⭐ Tekshirish uchun mypy / pyright / pydantic kerak")
print("\n=== 2. Konteyner turlari ===")
def konteynerlar(
a: list[int],
b: dict[str, float],
c: tuple[int, str], # aniq ikkita
d: tuple[int, ...], # cheksiz
e: set[str],
f: frozenset[int],
g: list[list[int]], # ichma-ich
h: dict[str, list[tuple[int, str]]],
) -> None:
...
print(f" {'Parametr':<10} {'Tur'}")
print(" " + "─" * 50)
for nom, tur in konteynerlar.__annotations__.items():
print(f" {nom:<10} {tur}")
print(f"""
⚠️ Eski sintaksis (3.9 gacha):
from typing import List, Dict, Tuple
def f(r: List[int]) -> Dict[str, int]: ...
✅ Zamonaviy (3.9+):
def f(r: list[int]) -> dict[str, int]: ...
""")
print("=== 3. Ixtiyoriy va birlashma ===")
def ixtiyoriy(
a: int | None, # 3.10+
b: str | bytes,
c: int | float | None = None,
d: list[int] | None = None,
) -> str | None:
...
print(f" Zamonaviy (3.10+):")
for nom, tur in ixtiyoriy.__annotations__.items():
print(f" {nom:<10} {tur}")
print(f"""
Eski:
from typing import Optional, Union
def f(a: Optional[int], b: Union[str, bytes]): ...
⭐ X | None ≡ Optional[X]
⚠️ Sukut None bo'lsa, turda ham None bo'lsin:
def f(x: int = None) ❌ mypy xato
def f(x: int | None = None) ✅
""")
print("=== 4. Funksiya turlari ===")
def yuqori_tartibli(
f: Callable[[int, int], int], # (int, int) -> int
g: Callable[[str], None], # (str) -> None
h: Callable[..., bool], # argumentlar noma'lum
predikat: Callable[[int], bool],
) -> Callable[[int], int]:
return lambda x: f(x, 1)
print(f" {'Parametr':<12} {'Tur'}")
print(" " + "─" * 44)
for nom, tur in yuqori_tartibli.__annotations__.items():
print(f" {nom:<12} {tur}")
print(f"\n Amaliy:")
print(f" key: Callable[[T], Any] sorted uchun")
print(f" callback: Callable[[Exception], None]")
print(f" factory: Callable[[], T] defaultdict uchun")
print("\n=== 5. collections.abc turlari ===")
def abc_turlari(
a: Iterable[int], # faqat iteratsiya
b: Iterator[str], # next() bor
c: Sequence[int], # indeks, len
d: Mapping[str, int], # o'qish uchun lug'at
) -> list[int]:
return sorted(a)
print(f" {'Tur':<24} {'Nima talab qiladi'}")
print(" " + "─" * 56)
TALABLAR = [
("Iterable[T]", "__iter__ — for bilan o'tish"),
("Iterator[T]", "__next__ — next() bilan"),
("Sequence[T]", "__getitem__, __len__ — indeks"),
("MutableSequence", "+ __setitem__, append"),
("Mapping[K, V]", "__getitem__, keys — o'qish"),
("MutableMapping", "+ __setitem__ — yozish"),
("Collection[T]", "__len__, __contains__, __iter__"),
]
for tur, izoh in TALABLAR:
print(f" {tur:<24} {izoh}")
print(f"""
⭐ QOIDA:
Argument → eng UMUMIY tur (Iterable)
Qaytarish → eng ANIQ tur (list)
def f(r: Iterable[int]) -> list[int]: ✅
def f(r: list[int]) -> Iterable[int]: ⚠️
""")
print("=== 6. TypeVar — generiklar ===")
T = TypeVar("T")
K = TypeVar("K")
V = TypeVar("V")
Son = TypeVar("Son", int, float) # cheklangan
Taqqoslanadigan = TypeVar("Taqqoslanadigan", bound="Taqqoslash")
def birinchi(r: Sequence[T]) -> T:
"""Turdan mustaqil."""
return r[0]
def juftlik(a: K, b: V) -> tuple[K, V]:
return a, b
def qosh(a: Son, b: Son) -> Son:
"""Faqat int yoki float."""
return a + b
def eng_katta(r: Sequence[T], kalit: Callable[[T], Any]) -> T:
return max(r, key=kalit)
print(f" birinchi([1, 2]) → {birinchi([1, 2])} (mypy: int)")
print(f" birinchi(['a', 'b']) → {birinchi(['a', 'b'])!r} (mypy: str)")
print(f" juftlik('a', 1) → {juftlik('a', 1)} (mypy: tuple[str, int])")
print(f" qosh(1, 2) → {qosh(1, 2)}")
print(f" qosh(1.5, 2.5) → {qosh(1.5, 2.5)}")
print(f"""
⭐ TypeVar — bitta turni "eslab qoladi":
birinchi([1,2]) → int
birinchi(["a"]) → str
⚠️ Any bilan bu ma'lumot YO'QOLADI:
def birinchi(r: list[Any]) -> Any # tur ma'lumoti yo'q
""")
print("=== 7. Protocol — duck typing ===")
class Uzunlikli(Protocol):
def __len__(self) -> int: ...
class Chizuvchi(Protocol):
def chiz(self) -> str: ...
class Taqqoslash(Protocol):
def __lt__(self, boshqa: Any) -> bool: ...
def hajm(x: Uzunlikli) -> int:
return len(x)
def chizish(x: Chizuvchi) -> str:
return x.chiz()
@dataclass
class Doira:
radius: float
def chiz(self) -> str:
return f"○ (r={self.radius})"
@dataclass
class Kvadrat:
tomon: float
def chiz(self) -> str:
return f"□ (a={self.tomon})"
print(f" hajm() — Uzunlikli protokol:")
for x in [[1, 2, 3], "abcde", {"a": 1}, {1, 2}]:
print(f" hajm({x!r:<12}) = {hajm(x)}")
print(f"\n chizish() — Chizuvchi protokol:")
for shakl in [Doira(5), Kvadrat(3)]:
print(f" {shakl.chiz()}")
print(f"""
⭐ Protocol — MEROS talab qilmaydi:
• Doira va Kvadrat hech narsadan meros olmagan
• Faqat `chiz()` metodi bor
• mypy buni tekshiradi
Bu — Pythonning "duck typing" falsafasiga mos.
""")
print("=== 8. Boshqa foydali turlar ===")
MAKSIMAL: Final = 100
Yol: TypeAlias = str
Sozlamalar: TypeAlias = dict[str, str | int | bool]
def literal_bilan(rejim: Literal["r", "w", "a"]) -> None:
...
def any_bilan(x: Any) -> Any:
"""⚠️ Any — tekshiruv O'CHADI."""
return x
def hech_qachon() -> "Never":
raise ValueError("har doim xato")
TURLAR = [
("Final", "MAKSIMAL: Final = 100", "qayta o'zlashtirmang"),
("TypeAlias", "Yol: TypeAlias = str", "taxallus"),
("Literal", 'Literal["r", "w"]', "aniq qiymatlar"),
("Any", "x: Any", "⚠️ tekshiruv o'chadi"),
("Never", "-> Never", "hech qachon qaytmaydi (3.11+)"),
("Self", "-> Self", "o'z sinfi (3.11+)"),
("LiteralString", "s: LiteralString", "SQL injection himoyasi (3.11+)"),
]
print(f" {'Tur':<16} {'Sintaksis':<26} {'Ma`nosi'}")
print(" " + "─" * 68)
for nom, sintaksis, izoh in TURLAR:
print(f" {nom:<16} {sintaksis:<26} {izoh}")
print("\n=== 9. ParamSpec — dekoratorlar ===")
from typing import ParamSpec
from functools import wraps
P = ParamSpec("P")
R = TypeVar("R")
def jurnal_typed(f: Callable[P, R]) -> Callable[P, R]:
"""✅ Imzo SAQLANADI."""
@wraps(f)
def ichki(*args: P.args, **kwargs: P.kwargs) -> R:
return f(*args, **kwargs)
return ichki
def jurnal_untyped(f):
"""⚠️ Imzo yo'qoladi (mypy uchun)."""
@wraps(f)
def ichki(*args, **kwargs):
return f(*args, **kwargs)
return ichki
@jurnal_typed
def hisobla(a: int, b: str = "x") -> list[str]:
return [b] * a
print(f" @jurnal_typed bilan:")
print(f" Imzo: {inspect.signature(hisobla)}")
print(f" Turlar: {hisobla.__annotations__}")
print(f" hisobla(3, 'a') = {hisobla(3, 'a')}")
print(f"""
⭐ ParamSpec (3.10+) — dekoratordan keyin ham
mypy argumentlar va qaytarish turini biladi.
ParamSpec siz:
Callable[..., Any] — tur ma'lumoti yo'q
""")Natijaning muhim qismi:
=== 1. Asosiy turlar ===
⚠️ Python TEKSHIRMAYDI:
kvadrat(5 ) → ✅ 10
kvadrat(2.5 ) → ✅ 5.0
kvadrat('ab' ) → ✅ 'abab'
kvadrat([1, 2] ) → ✅ [1, 2, 1, 2]
=== 2. Konteyner turlari ===
Parametr Tur
──────────────────────────────────────────────────
a list[int]
c tuple[int, str]
d tuple[int, ...]
h dict[str, list[tuple[int, str]]]
=== 7. Protocol — duck typing ===
hajm() — Uzunlikli protokol:
hajm([1, 2, 3] ) = 3
hajm('abcde' ) = 5
hajm({'a': 1} ) = 1Nima ko'rsatdi: 2.3, 2.4-bo'limlar.
Misol 3 — mypy va doctest
"""Statik tekshiruv va hujjatdagi testlar."""
import doctest
import subprocess
import sys
import tempfile
from pathlib import Path
print("=== 1. doctest asoslari ===")
def kvadrat(x: int) -> int:
"""Sonning kvadratini qaytaradi.
>>> kvadrat(5)
25
>>> kvadrat(-3)
9
>>> kvadrat(0)
0
"""
return x ** 2
def bol(a: float, b: float) -> float:
"""Ikki sonni bo'ladi.
>>> bol(10, 2)
5.0
>>> bol(1, 3)
0.3333333333333333
>>> bol(1, 0)
Traceback (most recent call last):
...
ZeroDivisionError: division by zero
"""
return a / b
def tozala(matn: str) -> str:
"""Matnni tozalaydi.
>>> tozala(" Salom DUNYO ")
'salom dunyo'
>>> tozala("")
''
"""
return " ".join(matn.split()).casefold()
natijalar = doctest.testmod(verbose=False)
print(f" Testlar: {natijalar.attempted}, xatolar: {natijalar.failed}\n")
print(f" Har funksiya uchun misollar:")
for f in [kvadrat, bol, tozala]:
misollar = [q.strip() for q in (f.__doc__ or "").splitlines()
if q.strip().startswith(">>>")]
print(f" {f.__name__:<12} {len(misollar)} ta misol")
for m in misollar:
print(f" {m}")
print("\n=== 2. ⚠️ doctest tuzoqlari ===")
print(""" ❌ set tartibi nomustaqil:
>>> {3, 1, 2}
{1, 2, 3} # ⚠️ har ishga tushirishda boshqa bo'lishi mumkin
✅ sorted() bilan:
>>> sorted({3, 1, 2})
[1, 2, 3]
❌ float aniqligi:
>>> 0.1 + 0.2
0.30000000000000004 # ⚠️ platformaga bog'liq bo'lishi mumkin
✅ round() yoki ELLIPSIS:
>>> round(0.1 + 0.2, 2)
0.3
>>> 0.1 + 0.2 # doctest: +ELLIPSIS
0.30000...
❌ id() yoki manzil:
>>> object()
<object object at 0x7f...> # ⚠️ har safar boshqa
✅ +ELLIPSIS bilan:
>>> object() # doctest: +ELLIPSIS
<object object at 0x...>
""")
def tuzoqlar_bilan() -> None:
"""doctest direktivalari.
>>> sorted({3, 1, 2})
[1, 2, 3]
>>> round(0.1 + 0.2, 2)
0.3
>>> 0.1 + 0.2 # doctest: +ELLIPSIS
0.30000...
>>> [1, 2, 3] # doctest: +NORMALIZE_WHITESPACE
[1, 2, 3]
>>> import random; random.random() # doctest: +SKIP
0.123456
"""
natija = doctest.run_docstring_examples(
tuzoqlar_bilan, {"sorted": sorted, "round": round}, verbose=False
)
print(f" Direktivali testlar bajarildi ✅")
DIREKTIVALAR = [
("+ELLIPSIS", "... — istalgan matn"),
("+NORMALIZE_WHITESPACE", "bo'sh joylar e'tiborsiz"),
("+SKIP", "o'tkazib yuborish"),
("+IGNORE_EXCEPTION_DETAIL", "istisno matnini tekshirmaslik"),
("+DONT_ACCEPT_TRUE_FOR_1", "True != 1"),
]
print(f"\n Direktivalar:")
for nom, izoh in DIREKTIVALAR:
print(f" {nom:<28} {izoh}")
print("\n=== 3. mypy simulyatsiyasi ===")
MYPY_KOD = '''
def kvadrat(x: int) -> int:
return x * 2
def notogri_qaytarish(x: int) -> str:
return x * 2 # xato: int qaytadi
def notogri_argument() -> None:
kvadrat("abc") # xato: str uzatildi
def yetishmayotgan_return(x: int) -> int:
if x > 0:
return x
# xato: barcha yo'lda return yo'q
def none_sukut(x: int = None) -> None: # xato: int | None bo'lishi kerak
pass
def ozgaruvchan_sukut(r: list[int] = []) -> None: # ⚠️ B006
pass
def togri(x: int | None = None) -> int:
return x if x is not None else 0
'''
print(f" Sinov kodi:\n")
for i, q in enumerate(MYPY_KOD.strip().splitlines(), 1):
print(f" {i:>2} │ {q}")
print(f"\n mypy kutilgan xatolari:")
KUTILGAN = [
(6, "Incompatible return value type (got \"int\", expected \"str\")"),
(10, "Argument 1 to \"kvadrat\" has incompatible type \"str\"; expected \"int\""),
(16, "Missing return statement"),
(19, "Incompatible default for argument \"x\" (default has type \"None\")"),
]
for qator, xabar in KUTILGAN:
print(f" {qator:>2}: error: {xabar}")
# Haqiqiy mypy bor bo'lsa ishga tushiramiz
try:
with tempfile.NamedTemporaryFile("w", suffix=".py", delete=False,
encoding="utf-8") as f:
f.write(MYPY_KOD)
yol = f.name
natija = subprocess.run(
[sys.executable, "-m", "mypy", "--no-color-output", yol],
capture_output=True, text=True, timeout=60,
)
if natija.returncode in (0, 1):
print(f"\n Haqiqiy mypy natijasi:")
for q in natija.stdout.splitlines()[:8]:
qisqa = q.split(":", 1)[-1] if ":" in q else q
print(f" {qisqa.strip()[:70]}")
Path(yol).unlink(missing_ok=True)
except (FileNotFoundError, subprocess.TimeoutExpired, OSError):
print(f"\n (mypy o'rnatilmagan — yuqoridagi kutilgan xatolar)")
print("\n=== 4. mypy bayroqlari ===")
BAYROQLAR = [
("--strict", "barcha qat'iy tekshiruvlar"),
("--disallow-untyped-defs", "har funksiyada tur bo'lsin"),
("--disallow-any-explicit", "Any ishlatmang"),
("--warn-return-any", "Any qaytarishni ogohlantir"),
("--warn-unused-ignores", "keraksiz type: ignore"),
("--check-untyped-defs", "tursiz funksiyalarni ham tekshir"),
("--no-implicit-optional", "x: int = None taqiqlansin"),
("--warn-unreachable", "yetib bo'lmaydigan kod"),
]
print(f" {'Bayroq':<30} {'Ma`nosi'}")
print(" " + "─" * 66)
for bayroq, izoh in BAYROQLAR:
print(f" {bayroq:<30} {izoh}")
print(f"""
pyproject.toml da:
[tool.mypy]
python_version = "3.12"
strict = true
warn_unused_ignores = true
exclude = ["build/", "tests/fixtures/"]
[[tool.mypy.overrides]]
module = "eski_modul.*"
ignore_errors = true
""")
print("=== 5. type: ignore ===")
print(""" Xatoni o'chirish:
x = f() # type: ignore ⚠️ hamma xatoni o'chiradi
x = f() # type: ignore[arg-type] ✅ aniq kod bilan
x = f() # type: ignore[arg-type,return] ✅ bir necha
⭐ Doim ANIQ kod yozing:
• Boshqa xato paydo bo'lsa ko'rinadi
• --warn-unused-ignores keraksizlarni topadi
Fayl darajasida:
# mypy: ignore-errors butun fayl
# mypy: disable-error-code="arg-type" bitta kod
""")
print("=== 6. Ish vaqtida tekshirish ===")
print(""" mypy — STATIK (yozish paytida).
Ish vaqtida tekshirish uchun boshqa vositalar:
1️⃣ pydantic — ma'lumot validatsiyasi:
from pydantic import BaseModel
class Foydalanuvchi(BaseModel):
ism: str
yosh: int
Foydalanuvchi(ism="Aziz", yosh="30") # ✅ "30" → 30
Foydalanuvchi(ism="Aziz", yosh="abc") # ❌ ValidationError
2️⃣ beartype — dekorator:
from beartype import beartype
@beartype
def f(x: int) -> str:
return str(x)
f("abc") # ❌ BeartypeCallHintParamViolation
3️⃣ typeguard — kontekst yoki dekorator
4️⃣ Qo'lda:
def f(x: int) -> str:
if not isinstance(x, int):
raise TypeError(f"int kutildi, {type(x).__name__} keldi")
return str(x)
""")
print(f" Qo'lda tekshiruvchi dekorator:\n")
from functools import wraps
import inspect as _inspect
def turlarni_tekshir(f):
"""Tur ko'rsatkichlariga qarab argumentlarni tekshiradi."""
sig = _inspect.signature(f)
@wraps(f)
def ichki(*args, **kwargs):
bound = sig.bind(*args, **kwargs)
bound.apply_defaults()
for nom, qiymat in bound.arguments.items():
p = sig.parameters[nom]
if p.annotation is _inspect.Parameter.empty:
continue
tur = p.annotation
if isinstance(tur, type) and not isinstance(qiymat, tur):
raise TypeError(
f"{f.__name__}(): {nom} — {tur.__name__} kutildi, "
f"{type(qiymat).__name__} keldi"
)
return f(*args, **kwargs)
return ichki
@turlarni_tekshir
def yosh_toifasi(yosh: int, prefiks: str = "") -> str:
return f"{prefiks}{'kattalar' if yosh >= 18 else 'bola'}"
SINOVLAR = [
((25,), {}),
((10,), {"prefiks": ">> "}),
(("25",), {}),
((25,), {"prefiks": 42}),
]
for args, kwargs in SINOVLAR:
try:
natija = f"✅ {yosh_toifasi(*args, **kwargs)!r}"
except TypeError as e:
natija = f"❌ {e}"
kod = f"yosh_toifasi{args}" + (f", **{kwargs}" if kwargs else "")
print(f" {kod:<34} {natija}")Natijaning muhim qismi:
=== 1. doctest asoslari ===
Testlar: 8, xatolar: 0
Har funksiya uchun misollar:
kvadrat 3 ta misol
>>> kvadrat(5)
>>> kvadrat(-3)
>>> kvadrat(0)
=== 3. mypy simulyatsiyasi ===
mypy kutilgan xatolari:
6: error: Incompatible return value type (got "int", expected "str")
10: error: Argument 1 to "kvadrat" has incompatible type "str"
16: error: Missing return statement
19: error: Incompatible default for argument "x"
=== 6. Ish vaqtida tekshirish ===
Qo'lda tekshiruvchi dekorator:
yosh_toifasi(25,) ✅ 'kattalar'
yosh_toifasi('25',) ❌ yosh_toifasi(): yosh — int kutildi,
str keldiNima ko'rsatdi: 2.5, 2.6-bo'limlar.
Misol 4 — Amaliy: to'liq hujjatlangan modul
"""Matn qayta ishlash kutubxonasi.
Bu modul o'zbek tilidagi matnlar bilan ishlash uchun
funksiyalar to'plamini taqdim etadi.
Asosiy funksiyalar:
normalla: Apostrof variantlarini birlashtiradi.
tozala: Ortiqcha bo'shliqlarni olib tashlaydi.
sozlarga: Matnni so'zlarga ajratadi.
tahlil: To'liq statistika.
Misol:
>>> tahlil("Salom dunyo!").sozlar
2
"""
from __future__ import annotations
import re
from collections import Counter
from collections.abc import Iterable, Callable
from dataclasses import dataclass, field
from typing import Final, Literal, NamedTuple, TypeAlias
# ─── Konstantalar ───
APOSTROFLAR: Final = "ʻʼ''`´"
"""O'zbek matnlarida uchraydigan apostrof variantlari."""
TOXTASH_SOZLARI: Final[frozenset[str]] = frozenset({
"va", "u", "bu", "shu", "uchun", "bilan", "lekin", "yoki",
"ham", "ni", "ning", "da", "dan", "ga", "sifatida",
})
"""Tahlildan chiqariladigan yordamchi so'zlar."""
Matn: TypeAlias = str
Registr: TypeAlias = Literal["saqlash", "kichik", "katta", "sarlavha"]
# ─── Natija turlari ───
class Statistika(NamedTuple):
"""Matn statistikasi.
Maydonlar:
belgilar: Jami belgilar soni.
sozlar: Jami so'zlar soni.
noyob: Noyob so'zlar soni.
ortacha_uzunlik: So'zlarning o'rtacha uzunligi.
leksik_boylik: noyob / sozlar nisbati (0.0 – 1.0).
"""
belgilar: int
sozlar: int
noyob: int
ortacha_uzunlik: float
leksik_boylik: float
@dataclass(frozen=True, slots=True)
class Sozlamalar:
"""Tahlil sozlamalari.
Atributlar:
toxtash_sozlari: Chiqariladigan so'zlar to'plami.
eng_kam_uzunlik: Bundan qisqa so'zlar tashlanadi.
registr: So'zlarni qanday normallashtirish.
apostrof_birlashtirish: Apostrof variantlarini birlashtirish.
"""
toxtash_sozlari: frozenset[str] = TOXTASH_SOZLARI
eng_kam_uzunlik: int = 2
registr: Registr = "kichik"
apostrof_birlashtirish: bool = True
def __post_init__(self) -> None:
if self.eng_kam_uzunlik < 1:
raise ValueError(
f"eng_kam_uzunlik musbat bo'lishi kerak: {self.eng_kam_uzunlik}"
)
SUKUT_SOZLAMALAR: Final = Sozlamalar()
# ─── Asosiy funksiyalar ───
def normalla(matn: Matn, /) -> Matn:
"""Apostrof variantlarini bitta shaklga keltiradi.
O'zbek matnlarida beshta turli apostrof belgisi uchraydi
(U+02BB, U+02BC, U+2018, U+2019, U+0060). Bu funksiya
ularning hammasini oddiy apostrof (U+0027) ga aylantiradi.
Argumentlar:
matn: Normallashtiriladigan matn.
Qaytaradi:
Apostroflari birlashtirilgan matn.
Misol:
>>> normalla("Oʻzbekiston")
"O'zbekiston"
>>> normalla("o'rik")
"o'rik"
"""
for belgi in APOSTROFLAR:
matn = matn.replace(belgi, "'")
return matn
def tozala(matn: Matn, /, *, registr: Registr = "saqlash") -> Matn:
"""Ortiqcha bo'shliqlarni olib tashlaydi.
Argumentlar:
matn: Tozalanadigan matn.
registr: Harflar registrini o'zgartirish usuli.
Qaytaradi:
Tozalangan matn.
Xatolar:
ValueError: registr noma'lum qiymat bo'lsa.
Misol:
>>> tozala(" Salom dunyo ")
'Salom dunyo'
>>> tozala(" SALOM ", registr="kichik")
'salom'
>>> tozala("salom dunyo", registr="sarlavha")
'Salom Dunyo'
"""
natija = " ".join(matn.split())
if registr == "saqlash":
return natija
if registr == "kichik":
return natija.casefold()
if registr == "katta":
return natija.upper()
if registr == "sarlavha":
return " ".join(s.capitalize() for s in natija.split())
raise ValueError(f"Noma'lum registr: {registr!r}")
def sozlarga(matn: Matn, /) -> list[str]:
"""Matnni so'zlarga ajratadi.
Faqat harflar va apostrofdan iborat ketma-ketliklar
so'z deb hisoblanadi. Raqamlar va tinish belgilari tashlanadi.
Argumentlar:
matn: Ajratiladigan matn.
Qaytaradi:
So'zlar ro'yxati.
Misol:
>>> sozlarga("Salom, dunyo! 42")
['Salom', 'dunyo']
>>> sozlarga("o'zbek tili")
["o'zbek", 'tili']
"""
return re.findall(r"[^\W\d_]+(?:'[^\W\d_]+)*", normalla(matn))
def filtrla(
sozlar: Iterable[str],
/,
*,
sozlamalar: Sozlamalar = SUKUT_SOZLAMALAR,
) -> list[str]:
"""So'zlarni sozlamalarga ko'ra filtrlaydi.
Argumentlar:
sozlar: Filtrlanadigan so'zlar.
sozlamalar: Filtr sozlamalari.
Qaytaradi:
Filtrlangan so'zlar ro'yxati.
Misol:
>>> filtrla(["salom", "va", "dunyo", "a"])
['salom', 'dunyo']
"""
natija = []
for soz in sozlar:
if sozlamalar.registr == "kichik":
soz = soz.casefold()
if len(soz) < sozlamalar.eng_kam_uzunlik:
continue
if soz in sozlamalar.toxtash_sozlari:
continue
natija.append(soz)
return natija
def tahlil(
matn: Matn,
/,
*,
sozlamalar: Sozlamalar = SUKUT_SOZLAMALAR,
) -> Statistika:
"""Matnning to'liq statistikasini hisoblaydi.
Argumentlar:
matn: Tahlil qilinadigan matn.
sozlamalar: Tahlil sozlamalari.
Qaytaradi:
Statistika obyekti (NamedTuple).
Misol:
>>> s = tahlil("Salom dunyo. Salom Python.")
>>> s.sozlar
4
>>> s.noyob
3
>>> round(s.leksik_boylik, 2)
0.75
"""
sozlar = filtrla(sozlarga(matn), sozlamalar=sozlamalar)
if not sozlar:
return Statistika(len(matn), 0, 0, 0.0, 0.0)
return Statistika(
belgilar=len(matn),
sozlar=len(sozlar),
noyob=len(set(sozlar)),
ortacha_uzunlik=sum(len(s) for s in sozlar) / len(sozlar),
leksik_boylik=len(set(sozlar)) / len(sozlar),
)
def eng_kop(
matn: Matn,
/,
n: int = 5,
*,
sozlamalar: Sozlamalar = SUKUT_SOZLAMALAR,
) -> list[tuple[str, int]]:
"""Eng ko'p uchraydigan so'zlarni qaytaradi.
Argumentlar:
matn: Tahlil qilinadigan matn.
n: Nechta so'z qaytarish.
sozlamalar: Tahlil sozlamalari.
Qaytaradi:
(so'z, soni) juftliklari, kamayish tartibida.
Misol:
>>> eng_kop("a a a b b c", n=2, sozlamalar=Sozlamalar(eng_kam_uzunlik=1))
[('a', 3), ('b', 2)]
"""
sozlar = filtrla(sozlarga(matn), sozlamalar=sozlamalar)
return Counter(sozlar).most_common(n)
def oxshashlik(a: Matn, b: Matn, /) -> float:
"""Ikki matn o'xshashligini hisoblaydi (Jaccard indeksi).
Argumentlar:
a: Birinchi matn.
b: Ikkinchi matn.
Qaytaradi:
0.0 (umuman boshqa) dan 1.0 (bir xil) gacha son.
Misol:
>>> oxshashlik("salom dunyo", "salom dunyo")
1.0
>>> oxshashlik("abc", "xyz")
0.0
"""
sa = set(filtrla(sozlarga(a)))
sb = set(filtrla(sozlarga(b)))
birlashma = sa | sb
return len(sa & sb) / len(birlashma) if birlashma else 1.0
# ═══ NAMOYISH ═══
if __name__ == "__main__":
import doctest
import inspect
print("=== 1. doctest ===\n")
natijalar = doctest.testmod(verbose=False)
print(f" Bajarildi: {natijalar.attempted} test")
print(f" Xatolar: {natijalar.failed}")
print(f" Holat: {'✅ hammasi o`tdi' if not natijalar.failed else '❌'}")
print("\n\n=== 2. Modul hujjati ===\n")
for q in (__doc__ or "").strip().splitlines()[:10]:
print(f" {q}")
print("\n\n=== 3. Funksiyalar ro'yxati ===\n")
FUNKSIYALAR = [normalla, tozala, sozlarga, filtrla,
tahlil, eng_kop, oxshashlik]
print(f" {'Funksiya':<14} {'Imzo':<44} {'Misol'}")
print(" " + "─" * 72)
for f in FUNKSIYALAR:
imzo = str(inspect.signature(f))
if len(imzo) > 42:
imzo = imzo[:40] + "…"
misollar = sum(1 for q in (f.__doc__ or "").splitlines()
if q.strip().startswith(">>>"))
print(f" {f.__name__:<14} {imzo:<44} {misollar}")
print("\n\n=== 4. Amaliy ishlatish ===\n")
MATN = """
Python — kuchli va oddiy dasturlash tili. Python o'rganish oson,
lekin uning imkoniyatlari juda keng. Dasturlash tili sifatida
Python veb va ma'lumot tahlilida ishlatiladi.
"""
s = tahlil(MATN)
print(f" Statistika:")
for nom, qiymat in s._asdict().items():
korinish = f"{qiymat:.2f}" if isinstance(qiymat, float) else str(qiymat)
print(f" {nom:<18} {korinish}")
print(f"\n Eng ko'p uchraganlar:")
for soz, n in eng_kop(MATN):
print(f" {soz:<14} {'█' * n} {n}")
MATN2 = """
JavaScript — veb dasturlash uchun til. JavaScript brauzerda
ishlaydi va veb sahifalarni interaktiv qiladi.
"""
print(f"\n O'xshashlik: {oxshashlik(MATN, MATN2):.1%}")
print(f"\n Sozlamalar bilan:")
qatiy = Sozlamalar(eng_kam_uzunlik=6, toxtash_sozlari=frozenset())
s2 = tahlil(MATN, sozlamalar=qatiy)
print(f" eng_kam_uzunlik=6: {s2.sozlar} so'z (sukut: {s.sozlar})")
print("\n\n=== 5. Tur ko'rsatkichlari ===\n")
print(f" {'Funksiya':<14} {'Tur ko`rsatkichlari'}")
print(" " + "─" * 62)
for f in FUNKSIYALAR:
turlar = ", ".join(
f"{k}: {getattr(v, '__name__', str(v))[:14]}"
for k, v in list(f.__annotations__.items())[:3]
)
print(f" {f.__name__:<14} {turlar[:46]}")
print(f"""
⭐ Bu modulda ishlatilgan:
• Modul docstringi (umumiy tavsif + misol)
• Har funksiyada Google uslubidagi docstring
• doctest misollari ({sum(1 for f in FUNKSIYALAR for q in (f.__doc__ or '').splitlines() if q.strip().startswith('>>>'))} ta)
• Tur ko'rsatkichlari (list[str], Iterable, TypeAlias, Final)
• Literal (registr uchun)
• NamedTuple (natija turi)
• frozen dataclass (sozlamalar)
• / va * (imzo nazorati)
• Konstantalar uchun docstring
""")
print("=== 6. Sifat mezonlari ===\n")
print("""
┌────────────────────────────────┬──────────────────────────────┐
│ Mezon │ Holat │
├────────────────────────────────┼──────────────────────────────┤
│ Modul docstringi │ ✅ tavsif + asosiy funksiyalar│
│ Har ommaviy funksiyada doc │ ✅ 7/7 │
│ Argumentlar hujjatlangan │ ✅ │
│ Qaytarish qiymati │ ✅ │
│ Xatolar (Raises) │ ✅ kerak bo'lganda │
│ Bajariladigan misollar │ ✅ doctest │
│ Tur ko'rsatkichlari │ ✅ hammasida │
│ mypy --strict │ ✅ toza │
│ Imzo nazorati (/, *) │ ✅ │
│ O'zgarmas sukutlar │ ✅ frozenset, frozen dataclass│
└────────────────────────────────┴──────────────────────────────┘
""")Natijaning muhim qismi:
=== 1. doctest ===
Bajarildi: 16 test
Xatolar: 0
Holat: ✅ hammasi o`tdi
=== 3. Funksiyalar ro'yxati ===
Funksiya Imzo Misol
────────────────────────────────────────────────────────────────────────
normalla (matn: 'Matn', /) -> 'Matn' 2
tozala (matn: 'Matn', /, *, registr: 'Registr' … 3
sozlarga (matn: 'Matn', /) -> 'list[str]' 2
tahlil (matn: 'Matn', /, *, sozlamalar: 'Sozlam… 4
=== 4. Amaliy ishlatish ===
Statistika:
belgilar 190
sozlar 19
noyob 15
ortacha_uzunlik 6.68
leksik_boylik 0.79
Eng ko'p uchraganlar:
python ███ 3
dasturlash ██ 2
tili ██ 2Nima ko'rsatdi: 2.1, 2.2, 2.3, 2.6, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Python tur ko'rsatkichlarini tekshiradi" | mypy yoki pydantic kerak |
| "Docstring — ixtiyoriy izoh" | __doc__, help(), doctest bilan bog'liq |
| "Har qatorda docstring bo'lsin" | Faqat birinchi buyruq |
"Optional[X] va X | None farqli" |
Bir xil |
"List[int] zamonaviy" |
3.9+ da list[int] |
"Any xavfsiz" |
Tur tekshiruvini o'chiradi |
| "Tur ko'rsatkichi tezlikni oshiradi" | Ish vaqtida ta'siri yo'q |
"doctest haqiqiy test o'rnini bosadi" |
Sodda misollar uchun; murakkab uchun pytest |
| "Docstring nima qilishini yozadi" | Nima uchun va noziklikni |
6. Keng tarqalgan xatolar va yechimlari
1. Docstring birinchi buyruq emas
def f():
x = 1
"""Docstring emas.""" # ❌
def f():
"""Docstring.""" # ✅
x = 12. x: int = None
def f(x: int = None): ... # ❌ mypy xato
def f(x: int | None = None): ... # ✅3. Eski tur sintaksisi
from typing import List
def f(r: List[int]): ... # ⚠️ 3.9 dan eskirgan
def f(r: list[int]): ... # ✅4. Any suiiste'moli
def f(x: Any) -> Any: ... # ⚠️ tekshiruv yo'q
def f(x: T) -> T: ... # ✅ TypeVar5. Argument uchun juda aniq tur
def f(r: list[int]) -> None: ... # ⚠️ tuple ham bo'lishi mumkin
def f(r: Iterable[int]) -> None: ... # ✅6. doctest da nomustaqil natija
>>> {3, 1, 2} # ⚠️ set tartibi
>>> sorted({3, 1, 2}) # ✅7. Docstring kodni takrorlaydi
"""a va b ni qo'shadi.""" # ⚠️ ravshan
"""Toshib ketishni tekshirmaydi.""" # ✅ nozik holat8. # type: ignore kodsiz
x = f() # type: ignore # ⚠️ hamma xatoni o'chiradi
x = f() # type: ignore[arg-type] # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 7.1-7.13-darslar (o'tilgan): butun 7-qism
- 8, 13-qismlar: sinflar,
dataclass,Protocol,Self - 10, 13-qismlar: dekoratorlar,
ParamSpec - 17-qism: testlash,
pytest,doctest - 13, 20-qismlar:
pydantic, API validatsiyasi - PEP 257 (docstring), PEP 484/526/585/604 (turlar)
- Vositalar:
mypy,pyright,ruff,sphinx,pdoc
8. Eng yaxshi amaliyotlar
Har ommaviy funksiyada docstring. Bir qatorli bo'lsa ham.
Docstring nima uchun va noziklikni tushuntiradi. Nima qilishini kod aytadi.
Loyihada bitta format. Google uslubi — eng keng tarqalgan.
Ommaviy API da tur ko'rsatkichlari. Kutubxona chegarasida majburiy.
Argument uchun umumiy, qaytarish uchun aniq tur.
Iterable[int]→list[int].Zamonaviy sintaksis.
list[int],int | None—List,Optionalemas.mypy --strictCI da. Bosqichma-bosqich qo'shing.Sodda misollar —
doctest. Ular hujjat ham, test ham.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
1. def f():
"""Doc."""
print(f.__doc__)
2. def f():
x = 1
"""Doc."""
print(f.__doc__)
3. def f(x: int) -> str: return x * 2
print(f(3))
4. def f(x: int) -> str: return x * 2
print(f("a"))
5. def f(a: int, b: str = "x") -> bool: ...
print(f.__annotations__)
6. from typing import Optional
print(Optional[int] == (int | None))
7. def f(x: list[int]): ...
print(f.__annotations__["x"])
8. import inspect
def f():
""" Doc.
Batafsil.
"""
print(repr(inspect.getdoc(f)))
9. def f() -> "list[int]": ...
print(f.__annotations__)
10. def f(x: int = None): ...
print(f())
11. from typing import TypeVar
T = TypeVar("T")
def f(x: T) -> T: return x
print(f(1), f("a"))
12. print(len.__doc__.splitlines()[0])Javoblar
Doc.None— birinchi buyruq emas6— Python tekshirmaydiaa—struchun ham ishlaydi{'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'bool'>}True— bir xillist[int]'Doc.\n\nBatafsil.'—getdocbirinchi qatordagi bo'shliqlarni olib tashlaydi va qolgan qatorlarning umumiy chekinishini tozalaydi{'return': 'list[int]'}— satr (kechiktirilgan)None— ishlaydi, lekinmypyogohlantiradi1 aReturn the number of items in a container.
Vazifa 2: Xatolarni tuzating
1. def f():
x = 1
"""Docstring."""
2. def f(x: int = None): ...
3. from typing import List, Dict
def f(r: List[int]) -> Dict[str, int]: ...
4. def f(x: Any) -> Any: return x
5. def f(r: list[int]) -> None: ... # tuple ham kerak
6. """
>>> {3, 1, 2}
{1, 2, 3}
"""
7. x = f() # type: ignore
8. def yigindi(a, b):
"""a va b ni qo'shadi."""
return a + bJavoblar
1. Docstringni birinchi qatorga ko'chiring
2. def f(x: int | None = None): ...
3. def f(r: list[int]) -> dict[str, int]: ...
4. T = TypeVar("T"); def f(x: T) -> T: return x
5. def f(r: Iterable[int]) -> None: ...
6. >>> sorted({3, 1, 2}) → [1, 2, 3]
7. x = f() # type: ignore[arg-type]
8. Docstring nozik holatni tushuntirsin yoki olib tashlansinVazifa 3: Modulni hujjatlash
Oldingi darslardagi biror modulingizni to'liq hujjatlang:
- Modul docstringi
- Har funksiyada Google uslubidagi docstring
- Tur ko'rsatkichlari (zamonaviy sintaksis)
doctestmisollarimypy --strictbilan tekshiringhelp()chiqishini ko'ring
Vazifa 4: Docstring linteri
Vosita yozing:
- Docstringsiz ommaviy funksiyalarni topsin
- Hujjatlanmagan parametrlarni
Returnsbo'limi yo'qligini (qaytarish qiymati bor bo'lsa)Raisesyo'qligini (raisebor bo'lsa)- PEP 257 buzilishlarini (nuqta, bo'sh qator)
- Hisobot va tuzatish takliflari
Vazifa 5: Tur ko'rsatkichlari auditi
- Modul funksiyalarini skanerlang
- Tur ko'rsatkichi yo'qlarini toping
Anyishlatilgan joylarni- Eski sintaksis (
List,Optional) - Juda aniq argument turlari (
list→Iterable) - Avtomatik tuzatish (
pyupgradekabi)
Vazifa 6: doctest to'plami
- 20+ funksiya uchun
doctestyozing - Nomustaqil natijalarni (
set,float) to'g'ri qayta ishlang - Istisnolarni tekshiring
- Direktivalarni ishlating (
ELLIPSIS,SKIP) pytest --doctest-modulesbilan ishga tushiring- Qamrovni o'lchang
Vazifa 7: O'ylash
Nega Python tur ko'rsatkichlarini ish vaqtida tekshirmaydi, garchi ular sintaksisning bir qismi bo'lsa ham?
Javob
To'rt sabab: tezlik, moslashuvchanlik, orqaga moslik va falsafa.
1. Tezlik.
Har chaqiruvda tur tekshiruvi — jiddiy narx:
def f(x: int, y: str, z: list[dict[str, int]]) -> bool: ...z ni tekshirish uchun butun tuzilmani aylanib chiqish kerak:
isinstance(z, list)
all(isinstance(d, dict) for d in z)
all(isinstance(k, str) and isinstance(v, int)
for d in z for k, v in d.items())Bu — O(n) yoki undan yomon, har chaqiruvda. Funksiya chaqiruvi Pythonda eng ko'p bajariladigan amal.
beartype bu muammoni tasodifiy namuna olish bilan hal qiladi (butun ro'yxatdan bittasini tekshiradi) — lekin bu ham kafolat bermaydi.
2. Moslashuvchanlik (duck typing).
Python falsafasi: "Agar u o'rdak kabi yursa va o'rdak kabi qichqirsa — u o'rdak."
def f(r: list[int]) -> int:
return sum(r)
f((1, 2, 3)) # tuple — ishlaydi
f({1, 2, 3}) # set — ishlaydi
f(range(3)) # range — ishlaydi
f(x for x in [1, 2]) # generator — ishlaydiQattiq tur tekshiruvi bularning hammasini taqiqlardi. Bu — Pythonning eng kuchli tomonini yo'q qilardi.
Protocol va collections.abc bu muammoni statik darajada hal qiladi:
def f(r: Iterable[int]) -> int: # ✅ hammasi mos3. Orqaga moslik.
Tur ko'rsatkichlari Python 3.0 da qo'shilgan (PEP 3107), lekin ma'nosiz annotatsiya sifatida:
def f(x: "istalgan narsa") -> 42: ... # ✅ ishlaydiPEP 484 (2014) ularga ma'no berdi, lekin xatti-harakatni o'zgartirmadi. Agar tekshiruv qo'shilsa:
- Millionlab qator kod buzilardi
- Ba'zi kutubxonalar annotatsiyani boshqa maqsadda ishlatadi
- Aylanma import muammolari paydo bo'lardi
4. Falsafa: "Bir vazifa — bir vosita".
Guido va Jukka Lehtosalo (mypy muallifi) ataylab ajratdilar:
| Vosita | Vazifa |
|---|---|
| Tur ko'rsatkichlari | Hujjat + statik tahlil |
mypy/pyright |
Statik tekshiruv |
pydantic/beartype |
Ish vaqtida validatsiya |
| Testlar | Xatti-harakat tekshiruvi |
Bu — moslashuvchan: siz kerakli darajani tanlaysiz.
Amaliy oqibatlar:
# Faqat hujjat
def f(x: int) -> str: ...
# + statik tekshiruv
$ mypy --strict
# + ish vaqtida (tashqi ma'lumot uchun)
@beartype
def f(x: int) -> str: ...
# yoki
class Model(BaseModel):
x: intQaysi tillar ish vaqtida tekshiradi:
| Til | Tur tekshiruvi |
|---|---|
| Java, C#, Rust, Go | Kompilyatsiya paytida (majburiy) |
| TypeScript | Kompilyatsiya paytida (JS ga o'chadi) |
| Python | (mypy — ixtiyoriy) |
| Ruby (Sorbet) | Ixtiyoriy, ish vaqtida ham |
| PHP 7+ | Qisman (skalyar turlar) |
TypeScript — eng yaqin analog:
function f(x: number): string {
return String(x);
}TypeScript ham ish vaqtida tekshirmaydi — turlar kompilyatsiyada o'chiriladi. Bu — bir xil falsafa.
Nima o'zgarishi mumkin:
PEP 563 (from __future__ import annotations) — annotatsiyalarni satr sifatida saqlash. Bu tezlikni oshiradi, lekin ish vaqtida tekshirishni qiyinlashtiradi.
PEP 649 (3.14 da) — kechiktirilgan hisoblash, __annotations__ kerak bo'lganda hisoblanadi. Bu — kompromis.
Ish vaqtida majburiy tekshiruv hech qachon taklif qilinmagan.
Xulosa: bu — ongli dizayn qarori. Tur ko'rsatkichlari — ixtiyoriy qatlam. Ular:
- Hujjat sifatida bepul foyda beradi
mypybilan xatolarni erta topadi- Ish vaqtida hech narsa qimmatga tushmaydi
- Duck typing va moslashuvchanlikni buzmaydi
Kerak bo'lsa — pydantic yoki beartype qo'shasiz. Kerak bo'lmasa — narx to'lamaysiz.
Nimani mustahkamlaydi: 2.3, 2.5-bo'limlar.
Xulosa
Bu darsda hujjatlash va tur ko'rsatkichlarini o'rgandik — va 7-qismni yakunladik.
Eng muhim uch fikr:
Docstring —
nima uchun, kod —nima. PEP 257: uch qo'shtirnoq, qisqa imperativ xulosa, ko'p qatorli bo'lsa bo'sh qator. Google formati — eng o'qiladigan.>>>misollaridoctestbilan bajariladigan test bo'ladi.Tur ko'rsatkichlari — hujjat va statik tahlil, ish vaqtida tekshiruv emas. Python ularni tekshirmaydi.
mypy --strictyozish paytida xatolarni topadi,pydantic/beartype— ish vaqtida. Zamonaviy sintaksis:list[int],int | None.Argument uchun umumiy tur, qaytarish uchun aniq.
def f(r: Iterable[int]) -> list[int]— chaqiruvchi istalgan iterable uzatadi, lekin natijaning aniq turini biladi.Protocolesa meros talab qilmasdan duck typing ni tur tizimiga olib kiradi.
7-QISM YAKUNI
Bu qismda funksiyalarni to'liq o'rgandik:
| Dars | Mavzu | Asosiy fikr |
|---|---|---|
| 1 | def |
Funksiya — obyekt, return yo'q → None |
| 2-6 | Argumentlar | Obyektga havola, sukut tuzog'i, / va * |
| 7 | return |
tuple, erta qaytish, finally tuzog'i |
| 8-9 | Qamrov | LEGB, UnboundLocalError, global/nonlocal |
| 10-12 | Funksional | lambda, birinchi darajali obyekt, map/filter |
| 13 | Rekursiya | Asos + qadam, @cache, chuqurlik chegarasi |
| 14 | Hujjat | Docstring, tur ko'rsatkichlari, mypy |
Uch umumiy tamoyil:
Funksiya — birinchi darajali obyekt. Uni uzatish, qaytarish, saqlash va o'zgartirish mumkin. Dekoratorlar, dispatch jadvallari, callback tizimlari — hammasi shunga tayanadi.
Imzo — ochiq shartnoma. Parametr tartibi, nomlari va sukut qiymatlari API ning bir qismi.
/bilan nomni yoping,*bilan nomlini majburiy qiling, tur ko'rsatkichlari bilan hujjatlang.Qamrov kompilyatsiya paytida aniqlanadi. Tanada o'zlashtirish bo'lsa — nom lokal. Bu
UnboundLocalErrorning sababi, yopilmalarning asosi vaglobal/nonlocalning zarurati.
Keyingi qism — 8-qism: OOP (Obyektga yo'naltirilgan dasturlash). U yerda sinflar, meros, maxsus metodlar, dataclass va Pythonning obyekt modelini chuqur o'rganamiz.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!