IlmHamroh
Python kursi/Funksiyalar5/14-dars32 daqiqa
Mundarija (21)

7.5-dars: *args va **kwargs

7-QISM — FUNKSIYALAR · 5-dars


1. Kirish va motivatsiya

Ba'zi funksiyalar oldindan noma'lum sondagi argument qabul qiladi:

python
print("a")
print("a", "b", "c")
print(*range(100))

max(1, 2)
max(1, 2, 3, 4, 5)

dict(a=1)
dict(a=1, b=2, c=3)

Buni qanday yozish mumkin?

python
def yigindi(*sonlar):
    return sum(sonlar)

yigindi()                   # 0
yigindi(1)                  # 1
yigindi(1, 2, 3, 4, 5)      # 15
python
def sozla(**sozlamalar):
    return sozlamalar

sozla(host="x", port=5432)  # {'host': 'x', 'port': 5432}

Lekin bu ikki belgi chalkash — ular ikki xil kontekstda ishlatiladi:

python
def f(*args): ...           # ta'rifda — YIG'ADI
f(*args)                    # chaqiruvda — OCHADI

Va nozikliklar bor:

python
def f(*args, **kwargs): ...
f(1, 2, a=3)                # args=(1,2), kwargs={'a':3}

def g(a, *args, b): ...
g(1, 2, 3)                  # ❌ b majburiy va faqat nomli

Bu darsda:

  • *args — cheksiz pozitsion argumentlar
  • **kwargs — cheksiz nomli argumentlar
  • Yig'ish vs ochish — bir belgi, ikki ma'no
  • Tartib qoidalari va to'liq imzo shakli
  • Argumentlarni yo'naltirish (forwarding)
  • Dekoratorlar va functools.wraps

2. Nazariya — chuqur tushuntirish

2.1. *args — pozitsion argumentlarni yig'ish

python
def f(*args):
    print(type(args), args)

f()                         # <class 'tuple'> ()
f(1)                        # <class 'tuple'> (1,)
f(1, 2, 3)                  # <class 'tuple'> (1, 2, 3)

args — har doim tuple (hatto bo'sh bo'lsa ham).

Oddiy parametrlar bilan:

python
def f(a, b, *args):
    return a, b, args

f(1, 2)                     # (1, 2, ())
f(1, 2, 3, 4)               # (1, 2, (3, 4))
f(1)                        # ❌ TypeError — b majburiy

*args dan keyin faqat nomli parametrlar:

python
def f(*args, b):            # b — FAQAT nomli
    return args, b

f(1, 2, b=3)                # ((1, 2), 3)
f(1, 2, 3)                  # ❌ TypeError: missing 1 required keyword-only argument: 'b'

Nom args — kelishuv, majburiyat emas:

python
def f(*sonlar): ...         # ✅ aniqroq
def f(*qiymatlar): ...      # ✅
def f(*args): ...           # ✅ umumiy holat uchun

Faqat * — argumentlarni yig'masdan chegara qo'yish (6-dars):

python
def f(a, *, b):             # b faqat nomli, qolgan pozitsion QABUL QILINMAYDI
    ...
f(1, b=2)                   # ✅
f(1, 2)                     # ❌ TypeError

2.2. **kwargs — nomli argumentlarni yig'ish

python
def f(**kwargs):
    print(type(kwargs), kwargs)

f()                         # <class 'dict'> {}
f(a=1)                      # <class 'dict'> {'a': 1}
f(a=1, b=2)                 # <class 'dict'> {'a': 1, 'b': 2}

kwargs — har doim dict, va tartib saqlanadi (PEP 468, Python 3.6+):

python
def f(**kwargs):
    return list(kwargs)

f(z=1, a=2, m=3)            # ['z', 'a', 'm']  ← yozilish tartibida

Oddiy parametrlar bilan:

python
def f(a, **kwargs):
    return a, kwargs

f(1, b=2, c=3)              # (1, {'b': 2, 'c': 3})
f(a=1, b=2)                 # (1, {'b': 2})

**kwargs — doim OXIRIDA:

python
def f(**kwargs, a): ...     # ❌ SyntaxError
def f(a, **kwargs): ...     # ✅

Faqat bitta **:

python
def f(**a, **b): ...        # ❌ SyntaxError

2.3. Yig'ish vs ochish

Bir xil belgi, ikki qarama-qarshi ma'no:

Kontekst * **
Ta'rifda Pozitsionlarni yig'adi → tuple Nomlilarni yig'adi → dict
Chaqiruvda Iterable'ni ochadi → pozitsion Lug'atni ochadi → nomli
python
def f(*args):               # YIG'ISH
    print(args)

r = [1, 2, 3]
f(*r)                       # OCHISH → f(1, 2, 3) → (1, 2, 3)
f(r)                        # OCHISH YO'Q → ([1, 2, 3],)

Chaqiruvda ochish (7.2-dars):

python
def g(a, b, c): ...

g(*[1, 2, 3])               # g(1, 2, 3)
g(**{"a": 1, "b": 2, "c": 3})
g(*[1, 2], **{"c": 3})

Boshqa joylarda ochish (PEP 448, Python 3.5+):

python
[*a, *b]                    # ro'yxatlarni birlashtirish
(*a, *b)                    # tuple
{*a, *b}                    # to'plam
{**d1, **d2}                # lug'at

[1, *r, 2]                  # o'rtaga qo'yish
{"a": 1, **d, "b": 2}

Ochishda ochish:

python
def f(*args):
    return args

f(*[1, 2], *[3, 4])         # (1, 2, 3, 4)  — bir necha marta ochish
f(*range(3), *"ab")         # (0, 1, 2, 'a', 'b')

2.4. To'liq imzo shakli

python
def f(a, b, /, c, d, *args, e, f=1, **kwargs):
    #  ─────    ────  ─────  ──────  ────────
    #  faqat    ikka  qolgan  faqat   qolgan
    #  pozits.  lasi  pozits. nomli   nomli
    ...

Tartib qat'iy:

  1. Faqat pozitsion (/ dan oldin)
  2. Pozitsion yoki nomli
  3. *args yoki *
  4. Faqat nomli
  5. **kwargs

Buzilsa — SyntaxError:

python
def f(**kwargs, a): ...             # ❌
def f(*args, a, *args2): ...        # ❌
def f(a, /, b, /, c): ...           # ❌ bitta /

Namunalar:

python
def f(*args): ...                   # faqat pozitsion (cheksiz)
def f(**kwargs): ...                # faqat nomli (cheksiz)
def f(*args, **kwargs): ...         # ⭐ hamma narsa
def f(a, *args): ...                # kamida bitta
def f(a, *, b): ...                 # b faqat nomli
def f(a, /, b): ...                 # a faqat pozitsion
def f(a, /, *, b): ...              # ⭐ eng qat'iy

inspect bilan:

python
import inspect
inspect.signature(f)
# (a, b, /, c, d, *args, e, f=1, **kwargs)

2.5. Argumentlarni yo'naltirish (forwarding)

Eng muhim qo'llanish:

python
def orash(*args, **kwargs):
    """Barcha argumentlarni asl funksiyaga o'tkazadi."""
    print(f"chaqirilmoqda: args={args}, kwargs={kwargs}")
    return asl(*args, **kwargs)

Dekorator asosi:

python
from functools import wraps

def jurnal(f):
    @wraps(f)
    def ichki(*args, **kwargs):
        print(f"{f.__name__} chaqirildi")
        return f(*args, **kwargs)
    return ichki

@wraps shart — aks holda metadata yo'qoladi:

python
def jurnal_yomon(f):
    def ichki(*args, **kwargs):
        return f(*args, **kwargs)
    return ichki

@jurnal_yomon
def salom(): ...

salom.__name__              # 'ichki'  ⚠️
salom.__doc__               # None     ⚠️

@wraps __name__, __doc__, __module__, __qualname__, __dict__, __wrapped__ ni ko'chiradi.

Meros bilan:

python
class Asos:
    def __init__(self, a, b): ...

class Voris(Asos):
    def __init__(self, c, *args, **kwargs):
        super().__init__(*args, **kwargs)        # ⭐ ota-onaga yo'naltirish
        self.c = c

Qisman o'zgartirish:

python
def kengaytir(f):
    @wraps(f)
    def ichki(*args, **kwargs):
        kwargs.setdefault("timeout", 30)         # sukut qo'shish
        return f(*args, **kwargs)
    return ichki

Yo'naltirish tur ko'rsatkichlarini yo'qotadi:

python
@jurnal
def qosh(a: int, b: int) -> int: ...

# IDE endi qosh(a, b) imzosini ko'rmaydi — (*args, **kwargs) ko'radi

Yechim — ParamSpec (Python 3.10+):

python
from typing import ParamSpec, TypeVar, Callable

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

14-darsda batafsil.

2.6. Amaliy naqshlar

1. Cheksiz argumentli funksiya:

python
def eng_katta(*sonlar, sukut=None):
    if not sonlar:
        return sukut
    return max(sonlar)

2. Ikkala shakl (iterable yoki alohida):

python
def yigindi(*args):
    """yigindi(1,2,3) va yigindi([1,2,3]) — ikkalasi ham."""
    if len(args) == 1 and hasattr(args[0], "__iter__"):
        return sum(args[0])
    return sum(args)

Bu — max, min naqshi:

python
max(1, 2, 3)
max([1, 2, 3])

3. Konfiguratsiyani yig'ish:

python
def ulan(host, port, **qolgan_sozlamalar):
    asosiy = {"host": host, "port": port}
    return {**asosiy, **qolgan_sozlamalar}

4. Ma'lum kalitlarni ajratish:

python
def f(**kwargs):
    debug = kwargs.pop("debug", False)
    timeout = kwargs.pop("timeout", 30)
    if kwargs:
        raise TypeError(f"Noma'lum argumentlar: {sorted(kwargs)}")
    ...

5. Ko'p funksiyaga tarqatish:

python
def yarat(**kwargs):
    oyna_args = {k: v for k, v in kwargs.items() if k.startswith("oyna_")}
    tugma_args = {k: v for k, v in kwargs.items() if k.startswith("tugma_")}
    ...

6. Standart kutubxonadan:

python
print(*values, sep=" ", end="\n", file=None, flush=False)
dict(**kwargs)
str.format(*args, **kwargs)
functools.partial(f, *args, **kwargs)

2.7. Kamchiliklar va cheklovlar

1. Imzo yo'qoladi:

python
def f(*args, **kwargs): ...
  • IDE avtoto'ldirish bermaydi
  • help(f) foydasiz
  • Tur ko'rsatkichlari yo'q
  • Xato faqat ish vaqtida

2. Xatolar kech chiqadi:

python
def f(**kwargs):
    return kwargs["hst"]            # ⚠️ "host" xato yozilgan

f(host="x")                         # ❌ KeyError ancha keyin

Yechim — tekshirish:

python
def f(**kwargs):
    RUXSAT = {"host", "port", "ssl"}
    notogri = set(kwargs) - RUXSAT
    if notogri:
        raise TypeError(f"Noma'lum argumentlar: {sorted(notogri)}")

3. Refaktoring qiyin:

python
f(*args, **kwargs)                  # qaysi argumentlar uzatilmoqda?

4. Hujjatlash qiyin:

python
def f(*args, **kwargs):
    """
    Argumentlar:
        *args: ???
        **kwargs: ???
    """

Qachon ishlatish:

Ishlating Ishlatmang
Dekoratorlar Oddiy funksiyalar
O'rash (wrapper) Ma'lum parametrlar
Meros (super()) Ko'p sukut qiymat
print kabi cheksiz Ixtiyoriy parametrlar
Qayta yo'naltirish API chegarasi

Muqobil:

python
def f(*args): ...                   # ⚠️
def f(sonlar: list[int]): ...       # ✅ aniqroq

def f(**kwargs): ...                # ⚠️
def f(*, a=1, b=2, c=3): ...        # ✅ aniq parametrlar
def f(sozlamalar: Sozlamalar): ...  # ✅ dataclass

3. Tez ma'lumotnoma

Yig'ish (ta'rifda)

python
def f(*args):       args — TUPLE (bo'sh bo'lsa ham)
def f(**kwargs):    kwargs — DICT (tartib saqlanadi)
def f(*args, **kwargs):     hamma narsa
def f(a, *args, b): b — FAQAT nomli
def f(a, *, b):     b — faqat nomli, qolgan pozitsion QABUL QILINMAYDI

Ochish (chaqiruvda)

python
f(*r)               iterable → pozitsion
f(**d)              lug'at → nomli
f(*a, *b)           bir necha marta
[*a, *b], {**d1, **d2}      PEP 448

To'liq tartib

python
def f(a, b, /, c, d, *args, e, f=1, **kwargs)
      ─────    ────  ─────  ──────  ────────
      1        2      3      4       5

1. faqat pozitsion (/ dan oldin)
2. pozitsion yoki nomli
3. *args yoki *
4. faqat nomli
5. **kwargs (OXIRIDA)

Yo'naltirish

python
from functools import wraps

def dekorator(f):
    @wraps(f)                   ⭐ metadata ko'chiradi
    def ichki(*args, **kwargs):
        return f(*args, **kwargs)
    return ichki

super().__init__(*args, **kwargs)       meros
kwargs.setdefault("timeout", 30)        sukut qo'shish

Kamchiliklar

Imzo yo'qoladi (IDE, help, tur ko'rsatkichlari)
Xatolar kech chiqadi (noma'lum kalit)
Refaktoring va hujjatlash qiyin

✅ Dekorator, o'rash, meros, print kabi
❌ Oddiy funksiya, ma'lum parametrlar

4. Batafsil misollar

Misol 1 — Asoslar

python
"""*args va **kwargs — barcha shakllar."""

import inspect

print("=== 1. *args ===")


def f(*args):
    return type(args).__name__, args


CHAQIRUVLAR = [
    "f()",
    "f(1)",
    "f(1, 2, 3)",
    "f(*[1, 2, 3])",
    "f([1, 2, 3])",
    "f(*range(3))",
    "f(*'abc')",
    "f(*[1, 2], *[3, 4])",
]

for kod in CHAQIRUVLAR:
    print(f"  {kod:<24} → {eval(kod)}")

print(f"\n  ⭐ args — har doim TUPLE, hatto bo'sh bo'lsa ham")


print("\n=== 2. **kwargs ===")


def g(**kwargs):
    return type(kwargs).__name__, kwargs


CHAQIRUVLAR = [
    "g()",
    "g(a=1)",
    "g(a=1, b=2)",
    "g(**{'a': 1, 'b': 2})",
    "g(z=1, a=2, m=3)",
    "g(**{'x': 1}, **{'y': 2})",
]

for kod in CHAQIRUVLAR:
    print(f"  {kod:<28} → {eval(kod)}")

print(f"\n  ⭐ kwargs — DICT, tartib SAQLANADI (PEP 468)")


print("\n=== 3. Ikkalasi birga ===")


def h(*args, **kwargs):
    return args, kwargs


CHAQIRUVLAR = [
    "h()",
    "h(1, 2)",
    "h(a=1, b=2)",
    "h(1, 2, a=3, b=4)",
    "h(*[1, 2], **{'a': 3})",
]

for kod in CHAQIRUVLAR:
    args, kwargs = eval(kod)
    print(f"  {kod:<28} → args={args}, kwargs={kwargs}")


print("\n=== 4. Oddiy parametrlar bilan ===")


def k(a, b=2, *args, c, d=4, **kwargs):
    return {"a": a, "b": b, "args": args, "c": c, "d": d, "kwargs": kwargs}


print(f"  def k(a, b=2, *args, c, d=4, **kwargs):\n")

CHAQIRUVLAR = [
    ("k(1, c=3)",                       lambda: k(1, c=3)),
    ("k(1, 20, c=3)",                   lambda: k(1, 20, c=3)),
    ("k(1, 20, 30, 40, c=3)",           lambda: k(1, 20, 30, 40, c=3)),
    ("k(1, c=3, d=40, x=5)",            lambda: k(1, c=3, d=40, x=5)),
    ("k(1, 2, 3)",                      lambda: k(1, 2, 3)),
]

for kod, fn in CHAQIRUVLAR:
    try:
        natija = fn()
        print(f"  {kod:<28}")
        for kalit, qiymat in natija.items():
            print(f"    {kalit:<8} = {qiymat!r}")
    except TypeError as x:
        print(f"  {kod:<28} ❌ TypeError: {x}")
    print()


print("=== 5. ⭐ Yig'ish vs ochish ===")


def yigadi(*args):
    return args


r = [1, 2, 3]

print(f"  r = {r}\n")
print(f"  Ta'rifda *args — YIG'ADI:")
print(f"    def f(*args): return args\n")
print(f"  Chaqiruvda * — OCHADI:")
print(f"    f(r)   → {yigadi(r)}       ← ochish YO'Q, bitta argument")
print(f"    f(*r)  → {yigadi(*r)}    ← ochildi, uchta argument")

print(f"\n  Boshqa joylarda ochish (PEP 448):")
a, b = [1, 2], [3, 4]
d1, d2 = {"a": 1}, {"b": 2}

OCHISHLAR = [
    ("[*a, *b]",            [*a, *b]),
    ("(*a, *b)",            (*a, *b)),
    ("{*a, *b}",            {*a, *b}),
    ("{**d1, **d2}",        {**d1, **d2}),
    ("[0, *a, 9]",          [0, *a, 9]),
    ("{'x': 0, **d1}",      {"x": 0, **d1}),
    ("[*range(3), *'ab']",  [*range(3), *"ab"]),
]

for kod, natija in OCHISHLAR:
    print(f"    {kod:<24} → {natija}")


print("\n=== 6. Tartib qoidalari ===")

TOGRI = [
    "def f(*args): ...",
    "def f(**kwargs): ...",
    "def f(*args, **kwargs): ...",
    "def f(a, *args): ...",
    "def f(a, *args, b): ...",
    "def f(a, *, b): ...",
    "def f(a, /, b): ...",
    "def f(a, /, b, *args, c, **kwargs): ...",
]

NOTOGRI = [
    "def f(**kwargs, a): ...",
    "def f(*args, *args2): ...",
    "def f(**a, **b): ...",
    "def f(a, /, b, /, c): ...",
    "def f(*, ): ...",
]

print(f"  ✅ To'g'ri:")
for kod in TOGRI:
    try:
        exec(kod)
        print(f"    {kod}")
    except SyntaxError:
        print(f"    ❌ {kod}")

print(f"\n  ❌ Noto'g'ri:")
for kod in NOTOGRI:
    try:
        exec(kod)
        print(f"    ✅ {kod}")
    except SyntaxError as x:
        print(f"    {kod:<32} {x.msg}")


print("\n=== 7. To'liq imzo ===")


def toliq(a, b, /, c, d=4, *args, e, f=6, **kwargs):
    ...


sig = inspect.signature(toliq)
print(f"  {sig}\n")

GURUHLAR = {
    "POSITIONAL_ONLY": "faqat pozitsion (/ dan oldin)",
    "POSITIONAL_OR_KEYWORD": "pozitsion yoki nomli",
    "VAR_POSITIONAL": "*args — qolgan pozitsion",
    "KEYWORD_ONLY": "faqat nomli (* dan keyin)",
    "VAR_KEYWORD": "**kwargs — qolgan nomli",
}

for kind, izoh in GURUHLAR.items():
    nomlar = [n for n, p in sig.parameters.items() if p.kind.name == kind]
    print(f"  {kind:<24} {str(nomlar):<16} {izoh}")

Natijaning muhim qismi:

text
=== 1. *args ===
  f()                      → ('tuple', ())
  f(1)                     → ('tuple', (1,))
  f(*[1, 2, 3])            → ('tuple', (1, 2, 3))
  f([1, 2, 3])             → ('tuple', ([1, 2, 3],))
  f(*[1, 2], *[3, 4])      → ('tuple', (1, 2, 3, 4))

=== 5. ⭐ Yig'ish vs ochish ===
    f(r)   → ([1, 2, 3],)       ← ochish YO'Q, bitta argument
    f(*r)  → (1, 2, 3)    ← ochildi, uchta argument

=== 6. Tartib qoidalari ===
  ❌ Noto'g'ri:
    def f(**kwargs, a): ...          arguments cannot follow var-keyword argument
    def f(*args, *args2): ...        * argument may appear only once
    def f(a, /, b, /, c): ...        / may appear only once

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

Misol 2 — Yo'naltirish va dekoratorlar

python
"""*args, **kwargs ning asosiy qo'llanishi."""

import time
import inspect
from functools import wraps

print("=== 1. Oddiy yo'naltirish ===")


def asl(a, b, c=3):
    return f"asl(a={a}, b={b}, c={c})"


def orash(*args, **kwargs):
    print(f"    → args={args}, kwargs={kwargs}")
    natija = asl(*args, **kwargs)
    print(f"    ← {natija}")
    return natija


CHAQIRUVLAR = [
    ("orash(1, 2)",             (1, 2), {}),
    ("orash(1, 2, 30)",         (1, 2, 30), {}),
    ("orash(1, b=2, c=30)",     (1,), {"b": 2, "c": 30}),
    ("orash(**{'a':1,'b':2})",  (), {"a": 1, "b": 2}),
]

for kod, args, kwargs in CHAQIRUVLAR:
    print(f"  {kod}")
    orash(*args, **kwargs)
    print()


print("=== 2. ⚠️ @wraps siz dekorator ===")


def jurnal_yomon(f):
    def ichki(*args, **kwargs):
        return f(*args, **kwargs)
    return ichki


def jurnal_yaxshi(f):
    @wraps(f)
    def ichki(*args, **kwargs):
        return f(*args, **kwargs)
    return ichki


@jurnal_yomon
def salom_yomon(ism: str, salom: str = "Salom") -> str:
    """Foydalanuvchini salomlaydi."""
    return f"{salom}, {ism}!"


@jurnal_yaxshi
def salom_yaxshi(ism: str, salom: str = "Salom") -> str:
    """Foydalanuvchini salomlaydi."""
    return f"{salom}, {ism}!"


ATRIBUTLAR = ["__name__", "__doc__", "__module__", "__qualname__"]

print(f"  {'Atribut':<14} {'@wraps siz':<26} {'@wraps bilan'}")
print("  " + "─" * 66)
for atr in ATRIBUTLAR:
    a = str(getattr(salom_yomon, atr, None))[:24]
    b = str(getattr(salom_yaxshi, atr, None))[:24]
    print(f"  {atr:<14} {a:<26} {b}")

print(f"\n  Imzo:")
print(f"    @wraps siz:   {inspect.signature(salom_yomon)}")
print(f"    @wraps bilan: {inspect.signature(salom_yaxshi)}   ⭐")

print(f"\n  Tur ko'rsatkichlari:")
print(f"    @wraps siz:   {getattr(salom_yomon, '__annotations__', {})}")
print(f"    @wraps bilan: {salom_yaxshi.__annotations__}")

print(f"\n  Asl funksiyaga kirish:")
print(f"    salom_yaxshi.__wrapped__ = {salom_yaxshi.__wrapped__.__name__}   ⭐")

print("""
  ⭐ @functools.wraps DOIM ishlating.
     U __name__, __doc__, __module__, __qualname__,
     __annotations__, __dict__ va __wrapped__ ni sozlaydi.
""")


print("\n=== 3. Foydali dekoratorlar ===")


def vaqt_olch(f):
    """Bajarilish vaqtini o'lchaydi."""
    @wraps(f)
    def ichki(*args, **kwargs):
        boshlandi = time.perf_counter()
        natija = f(*args, **kwargs)
        vaqt = time.perf_counter() - boshlandi
        print(f"    ⏱  {f.__name__}: {vaqt * 1000:.3f} ms")
        return natija
    return ichki


def qayta_urin(urinishlar=3, kutish=0.01):
    """Xato bo'lsa qayta urinadi."""
    def dekorator(f):
        @wraps(f)
        def ichki(*args, **kwargs):
            oxirgi_xato = None
            for i in range(1, urinishlar + 1):
                try:
                    return f(*args, **kwargs)
                except Exception as x:
                    oxirgi_xato = x
                    print(f"    ⚠️  {i}-urinish muvaffaqiyatsiz: {x}")
                    if i < urinishlar:
                        time.sleep(kutish)
            raise oxirgi_xato
        return ichki
    return dekorator


def sukutlar(**standart):
    """Yetishmayotgan nomli argumentlarga sukut qo'shadi."""
    def dekorator(f):
        @wraps(f)
        def ichki(*args, **kwargs):
            for k, v in standart.items():
                kwargs.setdefault(k, v)
            return f(*args, **kwargs)
        return ichki
    return dekorator


def tekshir(**qoidalar):
    """Argumentlarni tekshiradi."""
    def dekorator(f):
        sig = inspect.signature(f)

        @wraps(f)
        def ichki(*args, **kwargs):
            bound = sig.bind(*args, **kwargs)
            bound.apply_defaults()
            for nom, qoida in qoidalar.items():
                if nom not in bound.arguments:
                    continue
                qiymat = bound.arguments[nom]
                if not qoida(qiymat):
                    raise ValueError(
                        f"{f.__name__}: {nom}={qiymat!r} tekshiruvdan o'tmadi"
                    )
            return f(*args, **kwargs)
        return ichki
    return dekorator


@vaqt_olch
def sekin_ish(n):
    return sum(range(n))


print(f"  @vaqt_olch:")
sekin_ish(1_000_000)

print(f"\n  @qayta_urin(urinishlar=3):")

urinish_soni = [0]


@qayta_urin(urinishlar=3, kutish=0.001)
def beqaror():
    urinish_soni[0] += 1
    if urinish_soni[0] < 3:
        raise ConnectionError(f"ulanish yo'q (#{urinish_soni[0]})")
    return "muvaffaqiyat"


print(f"    natija: {beqaror()}")

print(f"\n  @sukutlar(timeout=30):")


@sukutlar(timeout=30, qayta_urin=True)
def sorov(url, timeout=None, qayta_urin=None):
    return f"GET {url} (timeout={timeout}, qayta_urin={qayta_urin})"


print(f"    sorov('http://x')          → {sorov('http://x')}")
print(f"    sorov('http://x', timeout=5) → {sorov('http://x', timeout=5)}")

print(f"\n  @tekshir(yosh=lambda x: 0 <= x <= 150):")


@tekshir(yosh=lambda x: 0 <= x <= 150, ism=lambda x: len(x) > 0)
def yarat(ism, yosh):
    return f"{ism} ({yosh})"


for args in [("Aziz", 30), ("Bobur", 200), ("", 25)]:
    try:
        print(f"    yarat{args} → {yarat(*args)}")
    except ValueError as x:
        print(f"    yarat{args} → ❌ {x}")


print("\n=== 4. Dekoratorlarni birlashtirish ===")


@vaqt_olch
@qayta_urin(urinishlar=2, kutish=0.001)
@sukutlar(rejim="tez")
def murakkab(x, rejim=None):
    return f"murakkab({x}, rejim={rejim})"


print(f"  @vaqt_olch")
print(f"  @qayta_urin(urinishlar=2)")
print(f"  @sukutlar(rejim='tez')")
print(f"  def murakkab(x, rejim=None):\n")
print(f"    murakkab(1) → {murakkab(1)}")

print(f"\n  ⭐ Har bir dekorator *args, **kwargs orqali")
print(f"     argumentlarni keyingisiga o'tkazadi.")

print(f"\n  Imzo saqlandi: {inspect.signature(murakkab)}")
print(f"  Nom saqlandi:  {murakkab.__name__}")


print("\n=== 5. Meros bilan yo'naltirish ===")


class Asos:
    def __init__(self, nom, yosh):
        self.nom = nom
        self.yosh = yosh

    def __repr__(self):
        return f"{type(self).__name__}({vars(self)})"


class Xodim(Asos):
    def __init__(self, maosh, *args, **kwargs):
        super().__init__(*args, **kwargs)        # ⭐ yo'naltirish
        self.maosh = maosh


class Menejer(Xodim):
    def __init__(self, jamoa, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.jamoa = jamoa


m = Menejer(jamoa=["Aziz", "Bobur"], maosh=10_000_000,
            nom="Aziza", yosh=35)
print(f"  Menejer(jamoa=[...], maosh=..., nom=..., yosh=...)")
print(f"    → {m}")

print(f"\n  MRO: {' → '.join(c.__name__ for c in type(m).__mro__[:-1])}")

print("""
  ⭐ *args, **kwargs bilan har sinf faqat O'Z parametrlarini
     biladi, qolganini ota-onaga o'tkazadi.
""")


print("\n=== 6. ⚠️ Yo'naltirish kamchiliklari ===")


@jurnal_yaxshi
def aniq(a: int, b: str = "x") -> str:
    return f"{a}{b}"


print(f"  @wraps bilan imzo ko'rinadi: {inspect.signature(aniq)}")
print(f"  Lekin ichki funksiya haqiqatda: (*args, **kwargs)\n")

print(f"  Xato ish vaqtida chiqadi:")
try:
    aniq(1, 2, 3)
except TypeError as x:
    print(f"    aniq(1, 2, 3) → ❌ {x}")

print("""
  ⚠️ Muammolar:
     • mypy dekoratordan keyin turlarni yo'qotadi (ParamSpec siz)
     • Xato faqat ish vaqtida
     • Debug qiyinroq (qo'shimcha freym)

  ⭐ Yechim — typing.ParamSpec (3.10+):

     P = ParamSpec("P")
     R = TypeVar("R")

     def dekorator(f: Callable[P, R]) -> Callable[P, R]:
         @wraps(f)
         def ichki(*args: P.args, **kwargs: P.kwargs) -> R:
             return f(*args, **kwargs)
         return ichki
""")

Natijaning muhim qismi:

text
=== 2. ⚠️ @wraps siz dekorator ===
  Atribut        @wraps siz                 @wraps bilan
  ──────────────────────────────────────────────────────────────────
  __name__       ichki                      salom_yaxshi
  __doc__        None                       Foydalanuvchini salomlay

  Imzo:
    @wraps siz:   (*args, **kwargs)
    @wraps bilan: (ism: str, salom: str = 'Salom') -> str   ⭐

=== 3. Foydali dekoratorlar ===
  @qayta_urin(urinishlar=3):
    ⚠️  1-urinish muvaffaqiyatsiz: ulanish yo'q (#1)
    ⚠️  2-urinish muvaffaqiyatsiz: ulanish yo'q (#2)
    natija: muvaffaqiyat

=== 5. Meros bilan yo'naltirish ===
  Menejer(jamoa=[...], maosh=..., nom=..., yosh=...)
    → Menejer({'nom': 'Aziza', 'yosh': 35, 'maosh': 10000000,
               'jamoa': ['Aziz', 'Bobur']})

Nima ko'rsatdi: 2.5-bo'lim.

Misol 3 — Amaliy naqshlar

python
"""*args va **kwargs ning kundalik qo'llanishi."""

import inspect
from collections.abc import Iterable

print("=== 1. Ikkala shakl (max/min naqshi) ===")


def yigindi(*args, sukut=0):
    """yigindi(1,2,3) va yigindi([1,2,3]) — ikkalasi ham."""
    if not args:
        return sukut
    if len(args) == 1 and isinstance(args[0], Iterable) and not isinstance(args[0], str):
        return sum(args[0], sukut)
    return sum(args, sukut)


SINOVLAR = [
    "yigindi()",
    "yigindi(1, 2, 3)",
    "yigindi([1, 2, 3])",
    "yigindi((1, 2, 3))",
    "yigindi(range(4))",
    "yigindi({1, 2, 3})",
    "yigindi(x for x in [1, 2])",
]

for kod in SINOVLAR:
    print(f"  {kod:<30} → {eval(kod)}")

print(f"\n  Standart kutubxonada:")
print(f"    max(1, 2, 3)     = {max(1, 2, 3)}")
print(f"    max([1, 2, 3])   = {max([1, 2, 3])}")
print(f"    max([1], default=0) = {max([1], default=0)}")


print("\n=== 2. Noma'lum argumentlarni tekshirish ===")


def ulan_yomon(**kwargs):
    """⚠️ Xato yozilgan kalit jimgina e'tiborsiz qoladi."""
    host = kwargs.get("host", "localhost")
    port = kwargs.get("port", 5432)
    ssl = kwargs.get("ssl", False)
    return f"{host}:{port} ssl={ssl}"


def ulan_yaxshi(**kwargs):
    """✅ Noma'lum kalitni topadi."""
    RUXSAT = {"host", "port", "ssl", "timeout"}
    notogri = set(kwargs) - RUXSAT
    if notogri:
        import difflib
        takliflar = []
        for n in sorted(notogri):
            mos = difflib.get_close_matches(n, RUXSAT, n=1, cutoff=0.6)
            takliflar.append(f"{n!r}" + (f" ({mos[0]!r} demoqchimidingiz?)" if mos else ""))
        raise TypeError(f"Noma'lum argumentlar: {', '.join(takliflar)}")

    return (f"{kwargs.get('host', 'localhost')}:{kwargs.get('port', 5432)} "
            f"ssl={kwargs.get('ssl', False)}")


SINOVLAR = [
    {"host": "db.uz", "port": 5432},
    {"host": "db.uz", "prot": 5432},        # xato yozilgan
    {"hots": "db.uz", "ssl": True},         # xato yozilgan
    {"host": "db.uz", "noma'lum": 1},
]

print(f"  {'Argumentlar':<38} {'Yomon':<22} {'Yaxshi'}")
print("  " + "─" * 76)
for kwargs in SINOVLAR:
    a = ulan_yomon(**kwargs)
    try:
        b = ulan_yaxshi(**kwargs)
    except TypeError as x:
        b = f"❌ {x}"
    print(f"  {str(kwargs)[:36]:<38} {a:<22} {b[:40]}")

print("""
  ⚠️ **kwargs xatolarni YASHIRADI — 'prot' jimgina e'tiborsiz qoldi.
  ⭐ Yaxshiroq: aniq parametrlar (* dan keyin) — Python o'zi tekshiradi.
""")


def ulan_eng_yaxshi(*, host="localhost", port=5432, ssl=False, timeout=30):
    """✅ Eng yaxshi — Python o'zi tekshiradi."""
    return f"{host}:{port} ssl={ssl} timeout={timeout}"


try:
    ulan_eng_yaxshi(prot=5432)
except TypeError as x:
    print(f"  ulan_eng_yaxshi(prot=5432) → ❌ {x}")


print("\n=== 3. Argumentlarni ajratish ===")


def yarat_oyna(**kwargs):
    """Prefiks bo'yicha argumentlarni ajratadi."""
    guruhlar = {}
    umumiy = {}
    for k, v in kwargs.items():
        if "_" in k:
            prefiks, qolgan = k.split("_", 1)
            guruhlar.setdefault(prefiks, {})[qolgan] = v
        else:
            umumiy[k] = v
    return umumiy, guruhlar


umumiy, guruhlar = yarat_oyna(
    sarlavha="Dastur",
    kenglik=800,
    oyna_rang="oq",
    oyna_ramka=True,
    tugma_matn="OK",
    tugma_rang="ko'k",
    tugma_kenglik=100,
)

print(f"  Umumiy: {umumiy}\n")
for prefiks, args in guruhlar.items():
    print(f"  {prefiks}_*: {args}")


print("\n=== 4. Ma'lum kalitlarni ajratish (pop) ===")


def qayta_ishla(malumot, **sozlamalar):
    """Ma'lum kalitlarni ajratib, qolganini o'tkazadi."""
    debug = sozlamalar.pop("debug", False)
    qatiy = sozlamalar.pop("qatiy", True)
    chegara = sozlamalar.pop("chegara", None)

    natija = {
        "malumot": malumot,
        "debug": debug,
        "qatiy": qatiy,
        "chegara": chegara,
        "qolgan": sozlamalar,
    }
    return natija


natija = qayta_ishla(
    [1, 2, 3],
    debug=True,
    chegara=10,
    boshqa_sozlama="x",
    yana_biri=42,
)

for k, v in natija.items():
    print(f"  {k:<10} = {v}")

print(f"\n  ⭐ pop() bilan ajratish — qolganini keyingi funksiyaga o'tkazish")


print("\n=== 5. Xavfsiz chaqirish (filtrlash) ===")


def xavfsiz_chaqir(f, *args, **kwargs):
    """Faqat f qabul qiladigan argumentlarni uzatadi."""
    sig = inspect.signature(f)
    ps = sig.parameters

    if any(p.kind is p.VAR_KEYWORD for p in ps.values()):
        return f(*args, **kwargs), set()

    mos = {k: v for k, v in kwargs.items() if k in ps}
    tashlangan = set(kwargs) - set(mos)
    return f(*args, **mos), tashlangan


def a_func(x, y=2):
    return f"a({x}, {y})"


def b_func(x, y=2, z=3):
    return f"b({x}, {y}, {z})"


def c_func(x, **qolgan):
    return f"c({x}, {qolgan})"


KWARGS = {"y": 20, "z": 30, "w": 40}

print(f"  kwargs = {KWARGS}\n")
print(f"  {'Funksiya':<10} {'Natija':<28} {'Tashlangan'}")
print("  " + "─" * 56)
for f in [a_func, b_func, c_func]:
    natija, tashlangan = xavfsiz_chaqir(f, 1, **KWARGS)
    print(f"  {f.__name__:<10} {natija:<28} {sorted(tashlangan) or '—'}")


print("\n=== 6. Konfiguratsiya birlashtirish ===")


def ulan(host, port, **qolgan):
    return {"host": host, "port": port, **qolgan}


STANDART = {"timeout": 30, "ssl": False, "pool": 5}
MUHIT = {"ssl": True, "host": "db.wisar.uz"}
CLI = {"port": 5433, "debug": True}

print(f"  STANDART = {STANDART}")
print(f"  MUHIT    = {MUHIT}")
print(f"  CLI      = {CLI}\n")

print(f"  ❌ Bir necha ** bir xil kalit bilan:")
try:
    ulan(**STANDART, **MUHIT, **CLI)
except TypeError as x:
    print(f"    ulan(**S, **M, **C) → {x}")

print(f"\n  ✅ Avval birlashtiring:")
birlashgan = {**STANDART, **MUHIT, **CLI}
print(f"    {{**S, **M, **C}} = {birlashgan}")
print(f"    ulan(**birlashgan) = {ulan(**birlashgan)}")

print(f"\n  ✅ Yoki | (3.9+):")
print(f"    ulan(**(S | M | C)) = {ulan(**(STANDART | MUHIT | CLI))}")


print("\n=== 7. print naqshi ===")


def chiqar(*qiymatlar, sep=" ", end="\n", prefiks="", tekislash=None):
    """print ga o'xshash, qo'shimcha imkoniyatlar bilan."""
    matn = sep.join(str(q) for q in qiymatlar)
    if tekislash:
        matn = f"{matn:{tekislash}}"
    print(f"{prefiks}{matn}", end=end)


print(f"  def chiqar(*qiymatlar, sep=' ', end='\\n', prefiks='', tekislash=None):\n")

chiqar("a", "b", "c", prefiks="    ")
chiqar(1, 2, 3, sep=" | ", prefiks="    ")
chiqar(*range(5), sep="-", prefiks="    ")
chiqar("markazda", tekislash="^30", prefiks="    [", end="]\n")

print(f"\n  ⭐ *qiymatlar dan keyin — hammasi FAQAT nomli.")
print(f"     Bu print, json.dumps, subprocess.run naqshi.")

import inspect
print(f"\n  print imzosi (o'xshash):")
print(f"    print(*values, sep=' ', end='\\n', file=None, flush=False)")

Natijaning muhim qismi:

text
=== 2. Noma'lum argumentlarni tekshirish ===
  Argumentlar                            Yomon                  Yaxshi
  ────────────────────────────────────────────────────────────────────────────
  {'host': 'db.uz', 'port': 5432}        db.uz:5432 ssl=False   db.uz:5432 ssl=False
  {'host': 'db.uz', 'prot': 5432}        db.uz:5432 ssl=False   ❌ Noma'lum argumentlar: 'prot' ('port' d

  ulan_eng_yaxshi(prot=5432) → ❌ ulan_eng_yaxshi() got an unexpected keyword argument 'prot'

=== 5. Xavfsiz chaqirish (filtrlash) ===
  Funksiya   Natija                       Tashlangan
  ────────────────────────────────────────────────────────
  a_func     a(1, 20)                     ['w', 'z']
  b_func     b(1, 20, 30)                 ['w']
  c_func     c(1, {'y': 20, 'z': 30, 'w': 40}) —

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

Misol 4 — Amaliy: plagin tizimi

python
"""*args va **kwargs bilan kengaytiriladigan tizim."""

import inspect
import time
from functools import wraps
from typing import Callable, Any

print("=== Hodisa tizimi (event system) ===\n")


class Hodisalar:
    """Obuna va xabar tarqatish tizimi."""

    def __init__(self):
        self._obunachi: dict[str, list[Callable]] = {}
        self._tarix: list[tuple] = []

    def obuna(self, hodisa: str):
        """Dekorator: funksiyani hodisaga bog'laydi."""
        def dekorator(f):
            self._obunachi.setdefault(hodisa, []).append(f)
            return f
        return dekorator

    def qosh(self, hodisa: str, f: Callable) -> None:
        self._obunachi.setdefault(hodisa, []).append(f)

    def tarqat(self, hodisa: str, *args, **kwargs) -> list:
        """⭐ Argumentlarni barcha obunachiga o'tkazadi."""
        self._tarix.append((hodisa, args, kwargs))
        natijalar = []
        for f in self._obunachi.get(hodisa, []):
            try:
                natijalar.append(self._xavfsiz_chaqir(f, *args, **kwargs))
            except Exception as x:
                natijalar.append(f"❌ {type(x).__name__}: {x}")
        return natijalar

    @staticmethod
    def _xavfsiz_chaqir(f, *args, **kwargs):
        """Faqat f qabul qiladigan argumentlarni uzatadi."""
        sig = inspect.signature(f)
        ps = sig.parameters

        # **kwargs bor — hammasini
        if any(p.kind is p.VAR_KEYWORD for p in ps.values()):
            return f(*args, **kwargs)

        # *args bor — barcha pozitsion
        if any(p.kind is p.VAR_POSITIONAL for p in ps.values()):
            mos_kw = {k: v for k, v in kwargs.items() if k in ps}
            return f(*args, **mos_kw)

        # Faqat mos keladiganlar
        pozitsion_soni = sum(
            1 for p in ps.values()
            if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)
        )
        mos_args = args[:pozitsion_soni]
        mos_kw = {k: v for k, v in kwargs.items()
                  if k in ps and ps[k].kind is not ps[k].POSITIONAL_ONLY}
        return f(*mos_args, **mos_kw)

    def statistika(self) -> dict:
        from collections import Counter
        return {
            "hodisalar": len(self._obunachi),
            "obunachi": sum(len(v) for v in self._obunachi.values()),
            "tarqatilgan": len(self._tarix),
            "eng_kop": Counter(h for h, _, _ in self._tarix).most_common(3),
        }


hodisalar = Hodisalar()


# ─── Obunachi funksiyalar — turli imzolar ───

@hodisalar.obuna("foydalanuvchi_kirdi")
def jurnalga_yoz(ism, **qolgan):
    """**kwargs bilan — hamma narsani oladi."""
    qosh = f", {qolgan}" if qolgan else ""
    return f"JURNAL: {ism} kirdi{qosh}"


@hodisalar.obuna("foydalanuvchi_kirdi")
def xabar_yubor(ism):
    """Faqat ism kerak."""
    return f"XABAR: Salom, {ism}!"


@hodisalar.obuna("foydalanuvchi_kirdi")
def statistika_yangila(ism, vaqt=None, ip=None):
    """Ba'zi qo'shimcha maydonlar."""
    return f"STATISTIKA: {ism} @ {vaqt or 'noma`lum'} ({ip or '—'})"


@hodisalar.obuna("xato")
def xatoni_yoz(*args, **kwargs):
    """Hamma narsani oladi."""
    return f"XATO: args={args}, kwargs={kwargs}"


@hodisalar.obuna("xato")
def ogohlantir(xabar, daraja="OGOH"):
    return f"{daraja}: {xabar}"


print("=== 1. Hodisa tarqatish ===\n")

print(f"  tarqat('foydalanuvchi_kirdi', 'Aziz', vaqt='10:00', ip='1.2.3.4')")
natijalar = hodisalar.tarqat(
    "foydalanuvchi_kirdi", "Aziz", vaqt="10:00", ip="1.2.3.4"
)
for n in natijalar:
    print(f"    {n}")

print(f"\n  tarqat('foydalanuvchi_kirdi', 'Bobur')")
for n in hodisalar.tarqat("foydalanuvchi_kirdi", "Bobur"):
    print(f"    {n}")

print(f"\n  tarqat('xato', 'Ulanish uzildi', daraja='XATO', kod=500)")
for n in hodisalar.tarqat("xato", "Ulanish uzildi", daraja="XATO", kod=500):
    print(f"    {n}")

print("""
  ⭐ Har obunachi FAQAT o'ziga kerakli argumentlarni oladi.
     Yangi maydon qo'shish eski obunachilarni buzmaydi.
""")


print("\n=== 2. Imzolarni solishtirish ===\n")

print(f"  {'Funksiya':<22} {'Imzo':<32} {'Qabul qiladi'}")
print("  " + "─" * 76)
for hodisa, funksiyalar in hodisalar._obunachi.items():
    for f in funksiyalar:
        sig = inspect.signature(f)
        ps = sig.parameters
        if any(p.kind is p.VAR_KEYWORD for p in ps.values()):
            qabul = "hammasini"
        else:
            qabul = ", ".join(ps)
        print(f"  {f.__name__:<22} {str(sig)[:30]:<32} {qabul}")


print("\n\n=== 3. Dekorator zanjiri ===\n")


def vaqt_olch(f):
    @wraps(f)
    def ichki(*args, **kwargs):
        boshlandi = time.perf_counter()
        natija = f(*args, **kwargs)
        ichki.oxirgi_vaqt = time.perf_counter() - boshlandi
        return natija
    ichki.oxirgi_vaqt = 0.0
    return ichki


def kesh(f):
    saqlangan = {}

    @wraps(f)
    def ichki(*args, **kwargs):
        kalit = (args, tuple(sorted(kwargs.items())))
        if kalit not in saqlangan:
            saqlangan[kalit] = f(*args, **kwargs)
            ichki.topilmadi += 1
        else:
            ichki.topildi += 1
        return saqlangan[kalit]

    ichki.topildi = ichki.topilmadi = 0
    ichki.tozala = saqlangan.clear
    return ichki


def sanaqchi(f):
    @wraps(f)
    def ichki(*args, **kwargs):
        ichki.chaqiruvlar += 1
        return f(*args, **kwargs)
    ichki.chaqiruvlar = 0
    return ichki


@sanaqchi
@kesh
@vaqt_olch
def ogir_hisob(n, daraja=2):
    """Qimmat hisoblash."""
    return sum(i ** daraja for i in range(n))


print(f"  @sanaqchi @kesh @vaqt_olch")
print(f"  def ogir_hisob(n, daraja=2):\n")

CHAQIRUVLAR = [
    ((100_000,), {}),
    ((100_000,), {}),
    ((100_000,), {"daraja": 3}),
    ((50_000,), {}),
    ((100_000,), {}),
]

for args, kwargs in CHAQIRUVLAR:
    natija = ogir_hisob(*args, **kwargs)
    kod = f"ogir_hisob({args[0]:,}" + (f", daraja={kwargs['daraja']})" if kwargs else ")")
    print(f"    {kod:<32} → {str(natija)[:14]}…")

print(f"\n  Statistika:")
print(f"    Chaqiruvlar:  {ogir_hisob.chaqiruvlar}")
print(f"    Kesh topildi: {ogir_hisob.__wrapped__.topildi}")
print(f"    Hisoblandi:   {ogir_hisob.__wrapped__.topilmadi}")

print(f"\n  Metadata saqlandi:")
print(f"    __name__:  {ogir_hisob.__name__}")
print(f"    __doc__:   {ogir_hisob.__doc__}")
print(f"    Imzo:      {inspect.signature(ogir_hisob)}")


print("\n\n=== 4. Plagin registratsiyasi ===\n")


class Registr:
    """Nom bo'yicha funksiyalarni saqlaydi."""

    def __init__(self, nom: str):
        self.nom = nom
        self._elementlar: dict[str, Callable] = {}

    def royxatga_ol(self, nom: str | None = None, **metadata):
        """Dekorator: funksiyani ro'yxatga oladi."""
        def dekorator(f):
            kalit = nom or f.__name__
            f._metadata = metadata
            self._elementlar[kalit] = f
            return f
        return dekorator

    def chaqir(self, nom: str, *args, **kwargs) -> Any:
        if nom not in self._elementlar:
            mavjud = ", ".join(sorted(self._elementlar))
            raise KeyError(f"{nom!r} topilmadi. Mavjud: {mavjud}")
        return self._elementlar[nom](*args, **kwargs)

    def __contains__(self, nom):
        return nom in self._elementlar

    def __len__(self):
        return len(self._elementlar)

    def royxat(self) -> list[tuple[str, dict]]:
        return [(n, getattr(f, "_metadata", {}))
                for n, f in sorted(self._elementlar.items())]


formatlar = Registr("formatlar")


@formatlar.royxatga_ol("json", kengaytma=".json", ikkilik=False)
def json_format(malumot, *, indent=2, sort_keys=False):
    import json
    return json.dumps(malumot, indent=indent, sort_keys=sort_keys,
                      ensure_ascii=False)


@formatlar.royxatga_ol("csv", kengaytma=".csv", ikkilik=False)
def csv_format(malumot, *, ajratgich=","):
    if not malumot:
        return ""
    ustunlar = list(malumot[0])
    qatorlar = [ajratgich.join(ustunlar)]
    qatorlar += [ajratgich.join(str(q.get(u, "")) for u in ustunlar)
                 for q in malumot]
    return "\n".join(qatorlar)


@formatlar.royxatga_ol("jadval", kengaytma=".txt", ikkilik=False)
def jadval_format(malumot, *, kenglik=12):
    if not malumot:
        return ""
    ustunlar = list(malumot[0])
    qatorlar = [" ".join(f"{u:<{kenglik}}" for u in ustunlar)]
    qatorlar.append("─" * (kenglik + 1) * len(ustunlar))
    qatorlar += [" ".join(f"{str(q.get(u, '')):<{kenglik}}" for u in ustunlar)
                 for q in malumot]
    return "\n".join(qatorlar)


MALUMOT = [
    {"ism": "Aziz", "bolim": "IT", "maosh": 7000000},
    {"ism": "Bobur", "bolim": "HR", "maosh": 5000000},
]

print(f"  Ro'yxatdan olingan formatlar ({len(formatlar)}):\n")
print(f"    {'Nom':<12} {'Metadata'}")
print("    " + "─" * 48)
for nom, meta in formatlar.royxat():
    print(f"    {nom:<12} {meta}")

print(f"\n  formatlar.chaqir('jadval', MALUMOT, kenglik=10):")
for q in formatlar.chaqir("jadval", MALUMOT, kenglik=10).splitlines():
    print(f"    {q}")

print(f"\n  formatlar.chaqir('csv', MALUMOT, ajratgich=' | '):")
for q in formatlar.chaqir("csv", MALUMOT, ajratgich=" | ").splitlines():
    print(f"    {q}")

print(f"\n  formatlar.chaqir('json', MALUMOT[:1], indent=4):")
for q in formatlar.chaqir("json", MALUMOT[:1], indent=4).splitlines():
    print(f"    {q}")

try:
    formatlar.chaqir("xml", MALUMOT)
except KeyError as x:
    print(f"\n  formatlar.chaqir('xml', ...) → ❌ {x}")


print("\n\n=== 5. Tizim statistikasi ===\n")

stat = hodisalar.statistika()
for k, v in stat.items():
    print(f"  {k:<14} {v}")

print("""
  ⭐ *args, **kwargs qayerda ishlatildi:

     Hodisalar.tarqat(hodisa, *args, **kwargs)
       → argumentlarni barcha obunachiga o'tkazish

     _xavfsiz_chaqir(f, *args, **kwargs)
       → har obunachiga faqat kerakli argumentlar

     Dekoratorlar: ichki(*args, **kwargs)
       → asl funksiyaga yo'naltirish

     Registr.chaqir(nom, *args, **kwargs)
       → dinamik funksiya chaqirish
""")

Natijaning muhim qismi:

text
=== 1. Hodisa tarqatish ===

  tarqat('foydalanuvchi_kirdi', 'Aziz', vaqt='10:00', ip='1.2.3.4')
    JURNAL: Aziz kirdi, {'vaqt': '10:00', 'ip': '1.2.3.4'}
    XABAR: Salom, Aziz!
    STATISTIKA: Aziz @ 10:00 (1.2.3.4)

=== 3. Dekorator zanjiri ===
    ogir_hisob(100,000)              → 333328333350…
    ogir_hisob(100,000)              → 333328333350…
    ogir_hisob(100,000, daraja=3)    → 249995000025…

  Statistika:
    Chaqiruvlar:  5
    Kesh topildi: 2
    Hisoblandi:   3

  Metadata saqlandi:
    __name__:  ogir_hisob
    Imzo:      (n, daraja=2)

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


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"args — ro'yxat" tuple
"kwargs tartibi tasodifiy" Saqlanadi (3.6+)
"* ta'rifda va chaqiruvda bir xil" Ta'rifda yig'adi, chaqiruvda ochadi
"f(*args) va f(args) bir xil" f(args) — bitta argument (tuple)
"*args dan keyin pozitsion mumkin" Faqat nomli
"**kwargs istalgan joyda" Doim oxirida
"@wraps ixtiyoriy" Metadata yo'qoladi — deyarli har doim kerak
"**kwargs — moslashuvchan API" Xatolarni yashiradi; aniq parametrlar yaxshiroq
"f(**d1, **d2) birlashtiradi" Umumiy kalit bo'lsa TypeError

6. Keng tarqalgan xatolar va yechimlari

1. Ochishni unutish

python
def f(*args): ...
r = [1, 2, 3]
f(r)                        # ⚠️ ([1,2,3],) — bitta argument
f(*r)                       # ✅ (1,2,3)

2. @wraps yo'q

python
def dek(f):
    def ichki(*a, **k): return f(*a, **k)      # ⚠️
    return ichki

def dek(f):
    @wraps(f)                                   # ✅
    def ichki(*a, **k): return f(*a, **k)
    return ichki

3. *args dan keyin pozitsion kutish

python
def f(*args, b): ...
f(1, 2, 3)                  # ❌ b majburiy va faqat nomli
f(1, 2, b=3)                # ✅

4. Noma'lum kalitlarni tekshirmaslik

python
def f(**kwargs):
    host = kwargs.get("host")       # ⚠️ "hots" jimgina e'tiborsiz

def f(*, host=None, port=None):     # ✅ Python o'zi tekshiradi

5. Bir necha ** bir xil kalit bilan

python
f(**d1, **d2)               # ❌ umumiy kalit bo'lsa
f(**{**d1, **d2})           # ✅

6. **kwargs oxirida emas

python
def f(**kwargs, a): ...     # ❌ SyntaxError
def f(a, **kwargs): ...     # ✅

7. Imzoni yo'qotish

python
def f(*args, **kwargs): ... # ⚠️ IDE va mypy yordam bermaydi
def f(a: int, b: str): ...  # ✅ aniq

8. Kesh kaliti sifatida kwargs

python
kalit = (args, kwargs)              # ❌ dict hashlanmaydi
kalit = (args, tuple(sorted(kwargs.items())))   # ✅
kalit = (args, frozenset(kwargs.items()))       # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 7.2, 7.4-darslar (o'tilgan): argumentlar, ochish
  • 7.6-dars: / va * — imzoni qat'iylashtirish
  • 8-qism: super().__init__(*args, **kwargs), metodlar
  • 10-qism: dekoratorlar, functools, partial
  • 14-dars: ParamSpec, tur ko'rsatkichlari
  • 6.5-dars (o'tilgan): tuple ochish
  • inspect: imzo tahlili, bind

8. Eng yaxshi amaliyotlar

  1. @functools.wraps — doim. Metadata va imzoni saqlaydi.

  2. *args, **kwargs — faqat yo'naltirish uchun. Oddiy funksiyada aniq parametrlar.

  3. **kwargs o'rniga * bilan aniq parametrlar. Python o'zi xatoni topadi.

  4. Noma'lum kalitlarni tekshiring. set(kwargs) - RUXSAT va aniq xato.

  5. Bir necha lug'atni avval birlashtiring. f(**{**d1, **d2}).

  6. args — tuple, kwargs — dict. Ularni o'zgartirish xavfsiz (lokal nusxa).

  7. Kesh kaliti uchun tuple(sorted(kwargs.items())).

  8. ParamSpec bilan turlarni saqlang (Python 3.10+).


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
def f(*args): return args
def g(**kw): return kw
def h(a, *args, b, **kw): return a, args, b, kw

1.  print(f())
2.  print(f([1, 2]))
3.  print(f(*[1, 2]))
4.  print(f(*[1, 2], *[3]))
5.  print(type(f()))
6.  print(g(z=1, a=2))
7.  print(list(g(z=1, a=2)))
8.  print(h(1, 2, 3, b=4, c=5))
9.  h(1, 2, 3, 4)
10. print(f(*"ab"))
11. print([*[1,2], *[3]], {**{"a":1}, **{"b":2}})
12. def k(*a, **kw): return len(a), len(kw)
    print(k(*range(3), **{"x": 1}))
Javoblar
  1. () — bo'sh tuple
  2. ([1, 2],) — bitta argument
  3. (1, 2) — ochildi
  4. (1, 2, 3) — ikki marta ochish
  5. <class 'tuple'>
  6. {'z': 1, 'a': 2} — tartib saqlanadi
  7. ['z', 'a']
  8. (1, (2, 3), 4, {'c': 5})
  9. TypeError — b faqat nomli va majburiy
  10. ('a', 'b')
  11. [1, 2, 3] {'a': 1, 'b': 2}
  12. (3, 1)

Vazifa 2: Xatolarni tuzating

python
1.  def f(*args): ...
    f(royxat)
2.  def dek(f):
        def ichki(*a, **k): return f(*a, **k)
        return ichki
3.  def f(*args, b): ...
    f(1, 2, 3)
4.  f(**d1, **d2)      # umumiy kalitlar bor
5.  def f(**kwargs, a): ...
6.  kesh[(args, kwargs)] = natija
7.  def f(**kwargs):
        host = kwargs.get("host")   # xato yozilgan kalitni topmaydi
8.  def qayta_ishla(*args, **kwargs): ...    # oddiy funksiya
Javoblar
python
1.  f(*royxat)
2.  @wraps(f) qo'shing
3.  f(1, 2, b=3)
4.  f(**{**d1, **d2})
5.  def f(a, **kwargs): ...
6.  kesh[(args, tuple(sorted(kwargs.items())))] = natija
7.  def f(*, host=None, port=None): ...
8.  def qayta_ishla(malumot: list, *, sozlamalar=None): ...

Vazifa 3: Dekoratorlar to'plami

Yozing (barchasi @wraps bilan):

  1. @vaqt_olch — bajarilish vaqti
  2. @qayta_urin(n, kutish) — xatoda qayta urinish
  3. @kesh(maxsize) — LRU kesh
  4. @tekshir(**qoidalar) — argument validatsiyasi
  5. @jurnal(daraja) — chaqiruvni yozish
  6. @chegaralangan(n, vaqt) — tezlikni cheklash
  7. Hammasini birlashtiring va imzo saqlanganini tekshiring

Vazifa 4: Moslashuvchan chaqiruvchi

xavfsiz_chaqir ni to'liq yozing:

  1. *args, **kwargs, /, * — barcha shakl
  2. Majburiy argument yetishmasa aniq xato
  3. Tur ko'rsatkichlariga qarab aylantirish
  4. Statistika: uzatilgan/tashlangan
  5. functools.singledispatch bilan solishtiring

Vazifa 5: Hodisa tizimi

4-misolni kengaytiring:

  1. Ustuvorlik (priority) bilan obuna
  2. Bir marta ishlaydigan obunachi (once)
  3. Filtr shartlari bilan obuna
  4. Asinxron obunachilar (async def)
  5. Xatolarni izolyatsiya qilish
  6. Hodisalar zanjiri (bir hodisa boshqasini chaqiradi)

Vazifa 6: Imzo moslashtiruvchi

Dekorator yozing:

python
@moslashtir(eski_imzo="(a, b, c)", yangi_imzo="(a, *, b, c)")
def f(a, *, b, c): ...
  1. Eski pozitsion chaqiruvlarni qo'llab-quvvatlasin
  2. DeprecationWarning bersin
  3. Yangi imzoga o'tkazsin
  4. Docstring ga eslatma qo'shsin
  5. inspect.signature to'g'ri ko'rsatsin

Vazifa 7: O'ylash

Nega Python *args uchun tuple, **kwargs uchun dict tanladi (list va boshqa emas)?

Javob

Ikki qaror, ikki sabab.

args — nega tuple:

1. O'zgarmaslik — himoya.

python
def f(*args):
    args.append(1)          # ❌ AttributeError

Agar args list bo'lganda, funksiya uni o'zgartira olardi. Bu — chalkash bo'lardi:

python
def f(*args):
    args[0] = 99            # chaqiruvchi ko'radimi? Yo'q, lekin chalkash

tuple bilan savol tug'ilmaydi.

2. Tezroq va tejamli.

python
sys.getsizeof(())           # 40
sys.getsizeof([])           # 56

Argumentlar to'plami — har chaqiruvda yaratiladi. tuple:

  • Kamroq xotira (allocated maydoni yo'q)
  • Tezroq yaratiladi
  • CPython uni maxsus optimallashtiradi

Funksiya chaqiruvi — eng ko'p bajariladigan amal, har nanosekund muhim.

3. Hashlanadi.

python
def kesh(f):
    saqlangan = {}
    def ichki(*args):
        if args not in saqlangan:       # ⭐ tuple hashlanadi
            saqlangan[args] = f(*args)
        return saqlangan[args]
    return ichki

list bo'lganda bu ishlamasdi — har safar tuple(args) yozish kerak bo'lardi.

4. Semantik: argumentlar — qat'iy yozuv.

tuple — heterogen, qat'iy tuzilma (6.5-dars). Argumentlar aynan shunday: har pozitsiya o'z ma'nosiga ega.

kwargs — nega dict:

1. Boshqa variant yo'q.

Nom → qiymat moslik uchun dict — yagona tabiiy tuzilma.

2. Nega frozendict emas?

Pythonda frozendict yo'q (bir necha marta taklif qilingan — PEP 416 rad etilgan).

Lekin dict bo'lgani ham foydali:

python
def dek(f):
    @wraps(f)
    def ichki(*args, **kwargs):
        kwargs.setdefault("timeout", 30)    # ⭐ o'zgartirish mumkin
        kwargs.pop("debug", None)
        return f(*args, **kwargs)
    return ichki

Dekoratorlarda kwargs ni o'zgartirish — juda keng tarqalgan naqsh.

3. Har chaqiruvda YANGI lug'at.

python
def f(**kwargs):
    kwargs["yangi"] = 1
    return kwargs

f(a=1)                      # {'a': 1, 'yangi': 1}
f(a=1)                      # {'a': 1, 'yangi': 1}  — toza

Bu — sukut qiymat tuzog'i (7.3-dars) emas: har chaqiruvda yangi lug'at.

4. Tartib saqlanadi (3.6+).

python
def f(**kwargs):
    return list(kwargs)

f(z=1, a=2)                 # ['z', 'a']

PEP 468 buni rasmiy kafolat qildi. Bu — dataclass, ORM, serializatsiya uchun muhim.

Nomuvofiqlik bormi?

Ha, kichik: args o'zgarmas, kwargs o'zgaruvchan. Bu — nomuvofiq ko'rinadi.

Lekin amaliy sabablari bor:

args kwargs
O'zgartirish kerakmi Kamdan-kam Tez-tez (dekoratorlarda)
Hashlanishi kerakmi Ha (kesh) Kamdan-kam
Tezlik muhimmi Ha Kamroq
Muqobil bormi list Yo'q

Amaliy natija:

python
def f(*args, **kwargs):
    args = list(args)               # o'zgartirish kerak bo'lsa
    args.append(1)

    kwargs["yangi"] = 1             # ✅ to'g'ridan-to'g'ri

    # Kesh kaliti
    kalit = (args_tuple, tuple(sorted(kwargs.items())))

Xulosa: har ikki tanlov — amaliy ehtiyojlardan kelib chiqqan. tuple argumentlarni himoyalaydi va keshlashni mumkin qiladi; dict dekoratorlarga argumentlarni o'zgartirish imkonini beradi. Nazariy izchillik amaliy foydaga qurbon qilingan — bu Pythonda tez-tez uchraydigan naqsh.

Nimani mustahkamlaydi: 2.1, 2.2, 2.5-bo'limlar.


Xulosa

Bu darsda *args va **kwargs ni o'rgandik.

Eng muhim uch fikr:

  1. Bir belgi, ikki ma'no. Ta'rifda *args argumentlarni yig'adi (tuple ga), chaqiruvda *r iterable'ni ochadi. ** uchun ham shunday: yig'ish → dict, ochish → nomli argumentlar.

  2. Asosiy qo'llanish — yo'naltirish. Dekoratorlar, o'rash funksiyalari, super().__init__(*args, **kwargs). Va bu yerda @functools.wraps majburiy — aks holda __name__, __doc__, imzo va tur ko'rsatkichlari yo'qoladi.

  3. Oddiy funksiyada ishlatmang. **kwargs xatolarni yashiradi (prot=5432 jimgina e'tiborsiz qoladi). Aniq parametrlar (* dan keyin) — Python o'zi tekshiradi, IDE yordam beradi, hujjat aniq bo'ladi.

Keyingi darsda / va * belgilarini ko'ramiz: faqat pozitsion va faqat nomli argumentlar — API dizaynining eng kuchli vositasi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
7.5-dars: args va kwargs — IlmHamroh