IlmHamroh
Python kursi/Funksiyalar14/14-dars39 daqiqa
Mundarija (22)

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:

python
def f(a, b, c=None):
    if c is None:
        c = []
    return [x for x in a if x > b] + c
python
def 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] + qoshimcha

Ikkinchisi uzunroq, lekin:

  • IDE avtoto'ldirish beradi
  • mypy xatolarni yozish paytida topadi
  • help() 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 tekshiruv
  • Optional, Union, Callable, TypeVar, Protocol
  • doctest — 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:

python
def f():
    """Bu — docstring."""
    ...

f.__doc__                       # 'Bu — docstring.'
help(f)                         # docstringni ko'rsatadi

Faqat birinchi buyruq:

python
def f():
    x = 1
    """Bu docstring EMAS."""    # oddiy satr ifodasi
f.__doc__                       # None

PEP 257 qoidalari:

python
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:

  1. Uch qo'shtirnoq ("""), hatto bir qatorli bo'lsa ham
  2. Birinchi qator — qisqa xulosa, nuqta bilan
  3. Ko'p qatorli bo'lsa — xulosadan keyin bo'sh qator
  4. Yopuvchi """ alohida qatorda
  5. Imperativ shakl: "Qaytaradi", "Hisoblaydi" — "Qaytaradigan" emas

Nima yozmaslik kerak:

python
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 NOZIKLIK

Docstring nima uchun va noziklikni tushuntiradi, nima qilishini emas — buni kod aytadi.

2.2. Docstring formatlari

Uch asosiy format:

1. Google uslubi (eng o'qiladigan):

python
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):

python
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):

python
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:

python
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

python
def f(a: int, b: str = "x", *args: float, c: bool = True,
      **kwargs: object) -> list[int]:
    ...

Python ularni TEKSHIRMAYDI:

python
def f(x: int) -> str:
    return x * 2

f("abc")                        # ✅ ishlaydi, "abcabc" qaytaradi

Tur ko'rsatkichi — hujjat va statik tahlil uchun.

__annotations__ da saqlanadi:

python
f.__annotations__               # {'x': <class 'int'>, 'return': <class 'str'>}

Asosiy turlar:

python
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):

python
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:

python
# 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:

python
def f(x: int = None): ...       # ⚠️ mypy: xato
def f(x: int | None = None): ...  # ✅

2.4. Murakkab turlar

Funksiyalar:

python
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:

python
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 kerak

Argument uchun eng umumiy tur, qaytarish uchun eng aniq:

python
def f(r: Iterable[int]) -> list[int]:           # ✅
    return sorted(r)

def f(r: list[int]) -> Iterable[int]:           # ⚠️ teskari

TypeVar — generiklar:

python
from typing import TypeVar

T = TypeVar("T")

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

birinchi([1, 2])                # int deb aniqlanadi
birinchi(["a"])                 # str

Chegara bilan:

python
Son = TypeVar("Son", int, float)

def qosh(a: Son, b: Son) -> Son:
    return a + b

Protocol — "duck typing" turi:

python
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:

python
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     # taxallus

Dekoratorlar (ParamSpec, 3.10+):

python
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 ichki

Bu — dekoratordan keyin imzo saqlanadi.

2.5. mypy — statik tekshiruv

bash
pip install mypy
mypy fayl.py
python
def f(x: int) -> str:
    return x * 2                # error: Incompatible return value type
                                # (got "int", expected "str")

Foydali bayroqlar:

bash
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 tekshir

pyproject.toml da:

toml
[tool.mypy]
python_version = "3.12"
strict = true
warn_unused_ignores = true

Xatoni o'chirish:

python
x = f()  # type: ignore
x = f()  # type: ignore[arg-type]       # ✅ aniq kod bilan

Muqobil 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:

python
# 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")   # ❌ ValidationError

beartype, typeguard — dekorator bilan tekshirish.

2.6. doctest

Docstring ichidagi >>> misollari — bajariladigan testlar:

python
def kvadrat(x: int) -> int:
    """Sonning kvadratini qaytaradi.

    >>> kvadrat(5)
    25
    >>> kvadrat(-3)
    9
    >>> kvadrat(0)
    0
    """
    return x ** 2
bash
python -m doctest fayl.py -v
python
import doctest
doctest.testmod()

Foydasi:

  • Misollar eskirmaydi (test buziladi)
  • Hujjat va test — bir joyda
  • help() da foydali misollar

Cheklovlar:

python
>>> {"b": 1, "a": 2}            # ✅ dict tartibi barqaror
{'b': 1, 'a': 2}

>>> {1, 2, 3}                   # ⚠️ set tartibi nomustaqil
{1, 2, 3}

>>> f()                         # ⚠️ float aniqligi
0.30000000000000004

Yechimlar:

python
>>> sorted({3, 1, 2})
[1, 2, 3]

>>> round(f(), 2)
0.3

>>> f()                         # doctest: +ELLIPSIS
0.30000...

>>> f()                         # doctest: +SKIP

Qachon doctest:

  • Sodda, aniq misollar
  • Hujjat sifatida qimmatli
  • Murakkab sozlash kerak (pytest ishlating)
  • 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:

python
def f(x: int) -> int:
    return x + 1                # ravshan, lekin zarar ham yo'q

for i: int in range(10): ...    # ❌ sintaksis yo'q

Bosqichma-bosqich qo'shish:

bash
mypy --check-untyped-defs       # avval mavjud kodni tekshiring
# keyin funksiyalarga tur qo'shing
mypy --disallow-untyped-defs    # oxirida majburiy qiling

Foydasi raqamlarda:

Dropbox (4 million qator Python) tur ko'rsatkichlariga o'tgach:

  • Refaktoring xavfsizroq
  • IDE yordami sezilarli yaxshilandi
  • Ish vaqtidagi TypeError lar kamaydi

Lekin: tur ko'rsatkichi test o'rnini bosmaydi.


3. Tez ma'lumotnoma

Docstring (PEP 257)

python
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 emas

Google formati

python
"""Qisqa xulosa.

Args:
    a: Izoh.
    b: Izoh.

Returns:
    Nima qaytaradi.

Raises:
    ValueError: Qachon.

Example:
    >>> f(1)
    2
"""

Tur ko'rsatkichlari

python
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

bash
mypy fayl.py
mypy --strict
mypy --disallow-untyped-defs

# type: ignore[kod]

doctest

python
"""
>>> f(5)
25
"""
python -m doctest fayl.py -v

⚠️ set tartibi, float aniqligi → sorted(), round(), +ELLIPSIS

4. Batafsil misollar

Misol 1 — Docstring

python
"""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:

text
=== 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

python
"""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:

text
=== 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}   ) = 1

Nima ko'rsatdi: 2.3, 2.4-bo'limlar.

Misol 3 — mypy va doctest

python
"""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:

text
=== 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 keldi

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

Misol 4 — Amaliy: to'liq hujjatlangan modul

python
"""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:

text
=== 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           ██ 2

Nima 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

python
def f():
    x = 1
    """Docstring emas."""       # ❌
def f():
    """Docstring."""            # ✅
    x = 1

2. x: int = None

python
def f(x: int = None): ...       # ❌ mypy xato
def f(x: int | None = None): ...  # ✅

3. Eski tur sintaksisi

python
from typing import List
def f(r: List[int]): ...        # ⚠️ 3.9 dan eskirgan
def f(r: list[int]): ...        # ✅

4. Any suiiste'moli

python
def f(x: Any) -> Any: ...       # ⚠️ tekshiruv yo'q
def f(x: T) -> T: ...           # ✅ TypeVar

5. Argument uchun juda aniq tur

python
def f(r: list[int]) -> None: ...        # ⚠️ tuple ham bo'lishi mumkin
def f(r: Iterable[int]) -> None: ...    # ✅

6. doctest da nomustaqil natija

python
>>> {3, 1, 2}                   # ⚠️ set tartibi
>>> sorted({3, 1, 2})           # ✅

7. Docstring kodni takrorlaydi

python
"""a va b ni qo'shadi."""       # ⚠️ ravshan
"""Toshib ketishni tekshirmaydi."""     # ✅ nozik holat

8. # type: ignore kodsiz

python
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

  1. Har ommaviy funksiyada docstring. Bir qatorli bo'lsa ham.

  2. Docstring nima uchun va noziklikni tushuntiradi. Nima qilishini kod aytadi.

  3. Loyihada bitta format. Google uslubi — eng keng tarqalgan.

  4. Ommaviy API da tur ko'rsatkichlari. Kutubxona chegarasida majburiy.

  5. Argument uchun umumiy, qaytarish uchun aniq tur. Iterable[int] → list[int].

  6. Zamonaviy sintaksis. list[int], int | None — List, Optional emas.

  7. mypy --strict CI da. Bosqichma-bosqich qo'shing.

  8. Sodda misollar — doctest. Ular hujjat ham, test ham.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
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
  1. Doc.
  2. None — birinchi buyruq emas
  3. 6 — Python tekshirmaydi
  4. aa — str uchun ham ishlaydi
  5. {'a': <class 'int'>, 'b': <class 'str'>, 'return': <class 'bool'>}
  6. True — bir xil
  7. list[int]
  8. 'Doc.\n\nBatafsil.' — getdoc birinchi qatordagi bo'shliqlarni olib tashlaydi va qolgan qatorlarning umumiy chekinishini tozalaydi
  9. {'return': 'list[int]'} — satr (kechiktirilgan)
  10. None — ishlaydi, lekin mypy ogohlantiradi
  11. 1 a
  12. Return the number of items in a container.

Vazifa 2: Xatolarni tuzating

python
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 + b
Javoblar
python
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 tashlansin

Vazifa 3: Modulni hujjatlash

Oldingi darslardagi biror modulingizni to'liq hujjatlang:

  1. Modul docstringi
  2. Har funksiyada Google uslubidagi docstring
  3. Tur ko'rsatkichlari (zamonaviy sintaksis)
  4. doctest misollari
  5. mypy --strict bilan tekshiring
  6. help() chiqishini ko'ring

Vazifa 4: Docstring linteri

Vosita yozing:

  1. Docstringsiz ommaviy funksiyalarni topsin
  2. Hujjatlanmagan parametrlarni
  3. Returns bo'limi yo'qligini (qaytarish qiymati bor bo'lsa)
  4. Raises yo'qligini (raise bor bo'lsa)
  5. PEP 257 buzilishlarini (nuqta, bo'sh qator)
  6. Hisobot va tuzatish takliflari

Vazifa 5: Tur ko'rsatkichlari auditi

  1. Modul funksiyalarini skanerlang
  2. Tur ko'rsatkichi yo'qlarini toping
  3. Any ishlatilgan joylarni
  4. Eski sintaksis (List, Optional)
  5. Juda aniq argument turlari (list → Iterable)
  6. Avtomatik tuzatish (pyupgrade kabi)

Vazifa 6: doctest to'plami

  1. 20+ funksiya uchun doctest yozing
  2. Nomustaqil natijalarni (set, float) to'g'ri qayta ishlang
  3. Istisnolarni tekshiring
  4. Direktivalarni ishlating (ELLIPSIS, SKIP)
  5. pytest --doctest-modules bilan ishga tushiring
  6. 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:

python
def f(x: int, y: str, z: list[dict[str, int]]) -> bool: ...

z ni tekshirish uchun butun tuzilmani aylanib chiqish kerak:

python
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."

python
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 — ishlaydi

Qattiq tur tekshiruvi bularning hammasini taqiqlardi. Bu — Pythonning eng kuchli tomonini yo'q qilardi.

Protocol va collections.abc bu muammoni statik darajada hal qiladi:

python
def f(r: Iterable[int]) -> int:     # ✅ hammasi mos

3. Orqaga moslik.

Tur ko'rsatkichlari Python 3.0 da qo'shilgan (PEP 3107), lekin ma'nosiz annotatsiya sifatida:

python
def f(x: "istalgan narsa") -> 42: ...       # ✅ ishlaydi

PEP 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:

python
# 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: int

Qaysi 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:

typescript
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
  • mypy bilan 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:

  1. 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. >>> misollari doctest bilan bajariladigan test bo'ladi.

  2. Tur ko'rsatkichlari — hujjat va statik tahlil, ish vaqtida tekshiruv emas. Python ularni tekshirmaydi. mypy --strict yozish paytida xatolarni topadi, pydantic/beartype — ish vaqtida. Zamonaviy sintaksis: list[int], int | None.

  3. Argument uchun umumiy tur, qaytarish uchun aniq. def f(r: Iterable[int]) -> list[int] — chaqiruvchi istalgan iterable uzatadi, lekin natijaning aniq turini biladi. Protocol esa 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:

  1. Funksiya — birinchi darajali obyekt. Uni uzatish, qaytarish, saqlash va o'zgartirish mumkin. Dekoratorlar, dispatch jadvallari, callback tizimlari — hammasi shunga tayanadi.

  2. 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.

  3. Qamrov kompilyatsiya paytida aniqlanadi. Tanada o'zlashtirish bo'lsa — nom lokal. Bu UnboundLocalError ning sababi, yopilmalarning asosi va global/nonlocal ning zarurati.

Keyingi qism — 8-qism: OOP (Obyektga yo'naltirilgan dasturlash). U yerda sinflar, meros, maxsus metodlar, dataclass va Pythonning obyekt modelini chuqur o'rganamiz.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
7.14-dars: Docstring va tur ko'rsatkichlari — IlmHamroh