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

7.2-dars: Argument va parametr

7-QISM — FUNKSIYALAR · 2-dars


1. Kirish va motivatsiya

Ikki so'z tez-tez chalkashtiriladi:

python
def salomlash(ism):         # ism — PARAMETR
    print(f"Salom, {ism}!")

salomlash("Aziz")           # "Aziz" — ARGUMENT

Parametr — funksiya ta'rifidagi nom. Argument — chaqiruvda uzatilgan qiymat.

Lekin asosiy savol boshqa: argument qanday uzatiladi?

python
def ozgartir(x):
    x = 99

a = 1
ozgartir(a)
print(a)                    # 1  ← o'zgarmadi
python
def ozgartir(r):
    r.append(99)

a = [1, 2]
ozgartir(a)
print(a)                    # [1, 2, 99]  ← o'zgardi!

Bir xil kod, turli natija. Nega?

Va yanada chalkash:

python
def ozgartir(r):
    r = [99]                # ⚠️ almashtirish

a = [1, 2]
ozgartir(a)
print(a)                    # [1, 2]  ← o'zgarmadi

Bu darsda:

  • Parametr vs argument — aniq farq
  • Uzatish mexanizmi — "obyektga havola bo'yicha uzatish"
  • O'zgaruvchan va o'zgarmas argumentlar
  • Xavfsiz naqshlar — argumentni buzmaslik
  • Argumentlar soni va tartibi
  • Ko'p parametrli funksiyalar muammosi

2. Nazariya — chuqur tushuntirish

2.1. Terminologiya

python
def f(a, b, c=3):           # a, b, c — PARAMETRLAR
    ...

f(1, 2)                     # 1, 2 — ARGUMENTLAR
f(1, b=2)                   # 1 — pozitsion argument, b=2 — nomli argument
Termin Ma'nosi
Parametr Funksiya ta'rifidagi nom
Argument Chaqiruvda uzatilgan qiymat
Pozitsion argument Tartib bo'yicha (f(1, 2))
Nomli argument Nom bilan (f(a=1))
Sukut qiymat Parametr uchun standart (c=3)

Ingliz tilida: parameter / argument. Ba'zan "formal parameter" va "actual parameter" deyiladi.

Amalda ko'pincha ikkalasi "argument" deyiladi — bu odatda muammo emas, lekin xato xabarlarida farq muhim:

python
def f(a, b): ...

f(1)
# TypeError: f() missing 1 required positional argument: 'b'
#                                                          ↑ parametr nomi

2.2. Uzatish mexanizmi

Klassik savol: Python "qiymat bo'yicha" (by value) yoki "havola bo'yicha" (by reference) uzatadimi?

Javob: ikkalasi ham emas. Python "obyektga havolani qiymat bo'yicha" uzatadi (call by object reference / call by sharing).

Nima sodir bo'ladi:

python
def f(x):
    ...

a = [1, 2]
f(a)
  1. a — obyektga yorliq (6.1-dars)
  2. f(a) chaqirilganda, x shu obyektga yangi yorliq bo'ladi
  3. Endi a va x — bitta obyektga ikki yorliq
a ──┐
    ├──→ [1, 2]
x ──┘

Ikki holat:

1. Obyektni O'ZGARTIRISH — ikkala yorliqda ko'rinadi:

python
def f(x):
    x.append(99)            # OBYEKTNI o'zgartiradi

a = [1, 2]
f(a)
print(a)                    # [1, 2, 99]  ✅ o'zgardi

2. Yorliqni QAYTA BOG'LASH — faqat lokal:

python
def f(x):
    x = [99]                # YORLIQNI boshqa obyektga bog'ladi

a = [1, 2]
f(a)
print(a)                    # [1, 2]  ← o'zgarmadi
Boshida:            f ichida x = [99] dan keyin:
a ──┐               a ──→ [1, 2]
    ├──→ [1, 2]     x ──→ [99]
x ──┘

Bu — Pythondagi eng muhim tushunchalardan biri.

O'zgarmas obyektlar bilan:

python
def f(x):
    x = 99                  # yagona imkoniyat — qayta bog'lash

a = 1
f(a)
print(a)                    # 1

int o'zgarmas, shuning uchun x += 1 ham qayta bog'lash:

python
def f(x):
    x += 1                  # x = x + 1 → yangi obyekt

a = 1
f(a)
print(a)                    # 1

Lekin ro'yxat bilan += — joyida:

python
def f(x):
    x += [99]               # list.__iadd__ → JOYIDA

a = [1, 2]
f(a)
print(a)                    # [1, 2, 99]  ⚠️ o'zgardi!

Bu — += ning ikki xil xatti-harakati (6.2-dars).

Jadval:

Amal O'zgarmas (int, str, tuple) O'zgaruvchan (list, dict, set)
x = yangi Lokal Lokal
x += y Lokal (yangi obyekt) Tashqarida ham (joyida)
x.metod() — (o'zgartiruvchi metod yo'q) Tashqarida ham
x[0] = y Xato Tashqarida ham

2.3. Xavfsiz naqshlar

1. Argumentni o'zgartirmang (afzal):

python
# ❌ Chaqiruvchini ajablantiradi
def qosh(r, x):
    r.append(x)
    return r

# ✅ Yangi obyekt
def qosh(r, x):
    return [*r, x]

2. Ataylab o'zgartirsangiz — None qaytaring:

python
def sarala_joyida(r) -> None:
    """Ro'yxatni JOYIDA saraladi."""
    r.sort()

Bu — Python kelishuvi (6.2-dars): list.sort(), list.append() — hammasi None qaytaradi.

3. Ichkarida nusxa oling:

python
def qayta_ishla(r):
    r = list(r)             # ⭐ lokal nusxa
    r.sort()
    return r

Sayoz nusxa — ichma-ich uchun yetarli emas (6.18-dars):

python
def qayta_ishla(d):
    d = copy.deepcopy(d)    # ichma-ich bo'lsa
    ...

4. O'zgarmas turlarni afzal ko'ring:

python
def f(teglar: frozenset): ...       # ✅ o'zgartirib bo'lmaydi
def f(nuqta: tuple): ...            # ✅

5. Hujjatda yozing:

python
def tozala(qatorlar: list[str]) -> None:
    """Ro'yxatni JOYIDA tozalaydi.

    ⚠️ Argument o'zgaradi!
    """

2.4. Argumentlar soni va tartibi

Pozitsion argumentlar — tartib muhim:

python
def bol(a, b):
    return a / b

bol(10, 2)                  # 5.0
bol(2, 10)                  # 0.2  ← boshqa natija

Soni mos kelishi kerak:

python
def f(a, b): ...

f(1)                        # ❌ TypeError: missing 1 required positional argument: 'b'
f(1, 2, 3)                  # ❌ TypeError: takes 2 positional arguments but 3 were given

Nomli argumentlar — tartib erkin:

python
bol(a=10, b=2)              # 5.0
bol(b=2, a=10)              # 5.0  ← bir xil

Nomli argumentlar pozitsiondan KEYIN:

python
f(1, b=2)                   # ✅
f(a=1, 2)                   # ❌ SyntaxError: positional argument follows keyword argument

Bir parametr ikki marta:

python
f(1, a=2)                   # ❌ TypeError: got multiple values for argument 'a'

Bu — 4-darsda batafsil.

2.5. Ko'p parametrli funksiyalar

python
def yarat_hisobot(malumot, sarlavha, kenglik, balandlik, rang,
                  shrift, hajm, chegara, fon, ramka, ...):

Muammolar:

  1. Tartibni eslash qiyin
  2. Chaqiruv o'qib bo'lmaydi: f(x, 1, True, None, 3, "a")
  3. Yangi parametr qo'shish — barcha chaqiruvni buzadi
  4. Test qilish qiyin

Yechimlar:

1. Nomli argumentlarni majburiy qilish (6-dars):

python
def yarat_hisobot(malumot, *, sarlavha, kenglik=80, rang="qora"):
    ...

yarat_hisobot(d, sarlavha="Hisobot", kenglik=100)    # ✅ o'qiladi
yarat_hisobot(d, "Hisobot", 100)                     # ❌ TypeError

2. Konfiguratsiya obyekti:

python
@dataclass
class HisobotSozlamalari:
    sarlavha: str
    kenglik: int = 80
    balandlik: int = 24
    rang: str = "qora"


def yarat_hisobot(malumot, sozlamalar: HisobotSozlamalari):
    ...

3. Guruhlash:

python
def yarat_hisobot(malumot, matn: MatnSozlamalari, uslub: UslubSozlamalari):
    ...

4. Funksiyani bo'lish:

Ko'p parametr — ko'pincha funksiya ko'p vazifa bajarayotganining belgisi.

Amaliy chegara: 3-4 pozitsion parametr. Undan ko'p bo'lsa — nomli argumentlar yoki obyekt.

2.6. Argumentlarni tekshirish

Turlarni tekshirish kerakmi?

python
def bol(a, b):
    if not isinstance(a, (int, float)):     # ⚠️ kerakmi?
        raise TypeError(...)
    return a / b

Python falsafasi — EAFP (3.8-dars):

python
def bol(a, b):
    return a / b            # ✅ noto'g'ri tur bo'lsa TypeError o'zi chiqadi

Python o'zi aniq xato beradi:

python
bol("a", 2)                 # TypeError: unsupported operand type(s)

Qachon tekshirish kerak:

1. Xato xabari tushunarsiz bo'lsa:

python
def yosh_toifasi(yosh):
    if yosh < 0:
        raise ValueError(f"Yosh manfiy bo'lolmaydi: {yosh}")
    ...

2. Xato kech chiqsa:

python
def qayta_ishla(malumot):
    # 1000 qator kod...
    natija = malumot["kalit"]           # ❌ KeyError bu yerda

def qayta_ishla(malumot):
    if "kalit" not in malumot:          # ✅ darhol
        raise ValueError("'kalit' maydoni majburiy")

3. Tashqi kirish (API, foydalanuvchi):

python
def api_handler(sorov: dict):
    yosh = sorov.get("yosh")
    if not isinstance(yosh, int) or not 0 <= yosh <= 150:
        raise ValueError("yosh 0-150 oralig'ida butun son bo'lishi kerak")

Tur ko'rsatkichlari — hujjat, tekshiruv emas:

python
def f(x: int) -> str: ...

f("satr")                   # ✅ ishlaydi — Python tekshirmaydi

Tekshirish uchun mypy (statik) yoki pydantic (ish vaqti) kerak. 14-darsda.

2.7. Argumentlarni ochish

* — ketma-ketlikni pozitsion argumentlarga:

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

args = (1, 2, 3)
f(*args)                    # f(1, 2, 3)

r = [1, 2, 3]
f(*r)                       # ✅ ro'yxat ham
f(*range(3))                # ✅ har qanday iterable

** — lug'atni nomli argumentlarga:

python
kwargs = {"a": 1, "b": 2, "c": 3}
f(**kwargs)                 # f(a=1, b=2, c=3)

Birga:

python
f(*[1, 2], **{"c": 3})      # f(1, 2, c=3)

Kalitlar parametr nomlariga mos kelishi kerak:

python
f(**{"x": 1})               # ❌ TypeError: got an unexpected keyword argument 'x'

Kalitlar satr bo'lishi kerak:

python
f(**{1: "a"})               # ❌ TypeError: keywords must be strings

Amaliy naqshlar:

python
# Konfiguratsiyani uzatish
sozlamalar = {"host": "x", "port": 5432}
ulan(**sozlamalar)

# Argumentlarni yo'naltirish
def orash(*args, **kwargs):
    return asl_funksiya(*args, **kwargs)

# Qisman qo'llash
from functools import partial
bol_10ga = partial(bol, b=10)

Bu — 5-darsda batafsil.


3. Tez ma'lumotnoma

Terminologiya

python
def f(a, b, c=3):       a, b, c — PARAMETRLAR
f(1, 2)                 1, 2 — ARGUMENTLAR
f(1, b=2)               1 — pozitsion, b=2 — nomli

Uzatish: obyektga havolani qiymat bo'yicha

python
def f(x):
    x.append(1)     ✅ TASHQARIDA ham ko'rinadi (obyekt o'zgardi)
    x = [1]         ❌ faqat lokal (yorliq qayta bog'landi)
    x += [1]        ⚠️ list — joyida, int/str/tuple — lokal
    x[0] = 1        ✅ tashqarida (o'zgaruvchan bo'lsa)

Xavfsiz naqshlar

python
def f(r): return [*r, x]        ✅ yangi obyekt
def f(r) -> None: r.append(x)   ✅ ataylab + None qaytaradi
def f(r): r = list(r); ...      ✅ ichkarida nusxa
def f(t: tuple): ...            ✅ o'zgarmas tur

Argumentlar tartibi

python
f(1, b=2)       ✅ pozitsion → nomli
f(a=1, 2)       ❌ SyntaxError
f(1, a=2)       ❌ TypeError: multiple values
f(1)            ❌ missing required positional argument

Ochish

python
f(*args)        ketma-ketlik → pozitsion
f(**kwargs)     lug'at → nomli (kalitlar SATR va parametr nomiga mos)
f(*a, **k)      birga

Ko'p parametr

3-4 dan ko'p → nomli argumentlar (*), dataclass, yoki funksiyani bo'ling

4. Batafsil misollar

Misol 1 — Uzatish mexanizmi

python
"""Argument qanday uzatiladi — to'liq namoyish."""

print("=== 1. ⭐ Asosiy farq ===")


def ozgartir(x):
    """Obyektni O'ZGARTIRADI."""
    x.append(99)


def qayta_boglash(x):
    """Yorliqni QAYTA BOG'LAYDI."""
    x = [99]


def ikkalasi(x):
    """Avval o'zgartiradi, keyin qayta bog'laydi."""
    x.append(99)
    x = [0]
    x.append(1)


for f, izoh in [(ozgartir, "x.append(99)"),
                (qayta_boglash, "x = [99]"),
                (ikkalasi, "x.append(99); x = [0]; x.append(1)")]:
    a = [1, 2]
    f(a)
    print(f"  def f(x): {izoh:<38} → a = {a}")

print("""
  ⭐ x.append(99)  — OBYEKTNI o'zgartiradi → tashqarida ko'rinadi
     x = [99]      — YORLIQNI qayta bog'laydi → faqat lokal
""")


print("\n=== 2. id() bilan kuzatish ===")


def kuzat(x, nom="x"):
    print(f"    {nom} kirishda:  id={id(x)}, qiymat={x}")
    x.append(99)
    print(f"    {nom} append'dan: id={id(x)}, qiymat={x}")
    x = [0]
    print(f"    {nom} = [0] dan:  id={id(x)}, qiymat={x}   ⚠️ YANGI id")


a = [1, 2]
print(f"  a tashqarida:     id={id(a)}, qiymat={a}\n")
kuzat(a)
print(f"\n  a chaqiruvdan keyin: id={id(a)}, qiymat={a}")

print("""
  ⭐ id o'zgargani — yorliq boshqa obyektga bog'langanini bildiradi.
     Asl obyekt (a) o'z joyida qoldi.
""")


print("\n=== 3. O'zgarmas vs o'zgaruvchan ===")

SINOVLAR = [
    ("int",     1,              lambda x: x + 1,        "x = x + 1"),
    ("str",     "abc",          lambda x: x + "d",      "x = x + 'd'"),
    ("tuple",   (1, 2),         lambda x: x + (3,),     "x = x + (3,)"),
    ("list",    [1, 2],         None,                   "x.append(3)"),
    ("dict",    {"a": 1},       None,                   "x['b'] = 2"),
    ("set",     {1, 2},         None,                   "x.add(3)"),
]


def sinov_ozgarmas(x, amal):
    x = amal(x)


def sinov_list(x):
    x.append(3)


def sinov_dict(x):
    x["b"] = 2


def sinov_set(x):
    x.add(3)


print(f"  {'Tur':<8} {'Amal':<18} {'Kirish':<14} {'Chiqish':<18} {'O`zgardimi'}")
print("  " + "─" * 74)

for tur, qiymat, amal, kod in SINOVLAR:
    asl = str(qiymat)
    if amal:
        sinov_ozgarmas(qiymat, amal)
    elif tur == "list":
        sinov_list(qiymat)
    elif tur == "dict":
        sinov_dict(qiymat)
    else:
        sinov_set(qiymat)
    ozgardi = "⚠️ HA" if str(qiymat) != asl else "✅ yo'q"
    print(f"  {tur:<8} {kod:<18} {asl:<14} {str(qiymat):<18} {ozgardi}")


print("\n=== 4. ⚠️ += tuzog'i ===")


def plus_teng(x):
    x += [99]


def plus_teng_son(x):
    x += 1


a = [1, 2]
plus_teng(a)
print(f"  def f(x): x += [99]")
print(f"    a = [1, 2] → {a}   ⚠️ O'ZGARDI (list.__iadd__ joyida)")

b = 1
plus_teng_son(b)
print(f"\n  def f(x): x += 1")
print(f"    b = 1 → {b}   ✅ o'zgarmadi (int yangi obyekt)")

print(f"\n  Sabab — bytecode:")
import dis
print(f"    Ro'yxat uchun:")
dis.dis("x += [1]")

print("""
  ⭐ x += y  →  x = x.__iadd__(y)  (agar __iadd__ bor bo'lsa)

     list.__iadd__ — JOYIDA o'zgartiradi va o'zini qaytaradi
     int da __iadd__ yo'q → x = x.__add__(y) → yangi obyekt
""")


print("\n=== 5. Ichma-ich tuzilmalar ===")


def sayoz_nusxa_bilan(d):
    """⚠️ Sayoz nusxa — ichki obyektlar umumiy."""
    d = dict(d)
    d["yangi"] = 1
    d["ichki"]["x"] = 99            # ⚠️ ASL o'zgaradi!
    return d


def chuqur_nusxa_bilan(d):
    """✅ Chuqur nusxa."""
    import copy
    d = copy.deepcopy(d)
    d["yangi"] = 1
    d["ichki"]["x"] = 99
    return d


for f, nom in [(sayoz_nusxa_bilan, "Sayoz"), (chuqur_nusxa_bilan, "Chuqur")]:
    asl = {"a": 1, "ichki": {"x": 0}}
    natija = f(asl)
    belgi = "⚠️" if asl["ichki"]["x"] == 99 else "✅"
    print(f"  {nom} nusxa:  asl = {asl}  {belgi}")

print("""
  ⚠️ dict(d) va d.copy() — SAYOZ.
     Ichma-ich bo'lsa copy.deepcopy() kerak (6.18-dars).
""")


print("\n=== 6. Xavfsiz naqshlar ===")

ASL = [3, 1, 2]

print(f"  Asl ro'yxat: {ASL}\n")


def yomon(r, x):
    """❌ Chaqiruvchini ajablantiradi."""
    r.append(x)
    return r


def yaxshi_1(r, x):
    """✅ Yangi ro'yxat."""
    return [*r, x]


def yaxshi_2(r, x) -> None:
    """✅ Ataylab joyida — None qaytaradi."""
    r.append(x)


def yaxshi_3(r):
    """✅ Ichkarida nusxa."""
    r = list(r)
    r.sort()
    return r


NAQSHLAR = [
    ("yomon(r, 9)",         yomon,      (9,)),
    ("yaxshi_1(r, 9)",      yaxshi_1,   (9,)),
    ("yaxshi_2(r, 9)",      yaxshi_2,   (9,)),
    ("yaxshi_3(r)",         yaxshi_3,   ()),
]

print(f"  {'Chaqiruv':<20} {'Qaytardi':<16} {'r keyin':<16} {'Xavfsizmi'}")
print("  " + "─" * 68)
for nom, f, qoshimcha in NAQSHLAR:
    r = ASL.copy()
    natija = f(r, *qoshimcha)
    xavfsiz = "✅" if r == ASL else "⚠️ o'zgardi"
    print(f"  {nom:<20} {str(natija):<16} {str(r):<16} {xavfsiz}")

print("""
  ⭐ Uch to'g'ri variant:
     1. Yangi obyekt qaytarish        — eng xavfsiz
     2. Joyida + None qaytarish       — aniq signal (6.2-dars kelishuvi)
     3. Ichkarida nusxa olish          — chaqiruvchi bilmaydi
""")

Natijaning muhim qismi:

text
=== 1. ⭐ Asosiy farq ===
  def f(x): x.append(99)                          → a = [1, 2, 99]
  def f(x): x = [99]                              → a = [1, 2]
  def f(x): x.append(99); x = [0]; x.append(1)    → a = [1, 2, 99]

=== 3. O'zgarmas vs o'zgaruvchan ===
  Tur      Amal               Kirish         Chiqish            O`zgardimi
  ──────────────────────────────────────────────────────────────────────────
  int      x = x + 1          1              1                  ✅ yo'q
  str      x = x + 'd'        abc            abc                ✅ yo'q
  tuple    x = x + (3,)       (1, 2)         (1, 2)             ✅ yo'q
  list     x.append(3)        [1, 2]         [1, 2, 3]          ⚠️ HA
  dict     x['b'] = 2         {'a': 1}       {'a': 1, 'b': 2}   ⚠️ HA
  set      x.add(3)           {1, 2}         {1, 2, 3}          ⚠️ HA

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

Misol 2 — Argumentlar tartibi va ochish

python
"""Pozitsion, nomli argumentlar va ularni ochish."""

print("=== 1. Pozitsion vs nomli ===")


def bol(a, b):
    """a / b"""
    return a / b


CHAQIRUVLAR = [
    ("bol(10, 2)",          lambda: bol(10, 2)),
    ("bol(2, 10)",          lambda: bol(2, 10)),
    ("bol(a=10, b=2)",      lambda: bol(a=10, b=2)),
    ("bol(b=2, a=10)",      lambda: bol(b=2, a=10)),
    ("bol(10, b=2)",        lambda: bol(10, b=2)),
]

for kod, f in CHAQIRUVLAR:
    print(f"  {kod:<22} → {f()}")

print(f"\n  ⭐ Pozitsion: TARTIB muhim")
print(f"     Nomli:     tartib ERKIN, lekin o'qilishi yaxshiroq")


print("\n=== 2. Xatolar ===")

XATOLAR = [
    ("bol(1)",              "bol(1)"),
    ("bol(1, 2, 3)",        "bol(1, 2, 3)"),
    ("bol(1, a=2)",         "bol(1, a=2)"),
    ("bol(x=1, y=2)",       "bol(x=1, y=2)"),
]

for nom, kod in XATOLAR:
    try:
        eval(kod)
        natija = "✅"
    except TypeError as x:
        natija = f"❌ TypeError: {x}"
    print(f"  {nom:<20} {natija}")

print(f"\n  bol(a=1, 2):")
try:
    eval("bol(a=1, 2)")
except SyntaxError as x:
    print(f"    ❌ SyntaxError: {x.msg}")

print("""
  ⭐ Qoida: pozitsion argumentlar NOMLIDAN OLDIN
""")


print("\n=== 3. Nomli argumentlar o'qilishni yaxshilaydi ===")


def yarat_tugma(matn, kenglik, balandlik, faol, korinmas, ramka):
    return (f"Tugma({matn!r}, {kenglik}×{balandlik}, "
            f"faol={faol}, korinmas={korinmas}, ramka={ramka})")


print(f"  ❌ Faqat pozitsion:")
print(f"    yarat_tugma('OK', 100, 30, True, False, True)")
print(f"    → nima True? nima False?\n")

print(f"  ✅ Nomli argumentlar bilan:")
print(f"    yarat_tugma('OK', kenglik=100, balandlik=30,")
print(f"                faol=True, korinmas=False, ramka=True)")
print(f"    → {yarat_tugma('OK', kenglik=100, balandlik=30, faol=True, korinmas=False, ramka=True)}")

print(f"\n  ⚠️ Bool argumentlar ayniqsa muhim:")
print(f"     f(x, True, False, True)       ❌ o'qib bo'lmaydi")
print(f"     f(x, faol=True, ...)          ✅")


print("\n=== 4. ⭐ * bilan ochish ===")


def uchburchak(a, b, c):
    return f"Uchburchak({a}, {b}, {c}), perimetr={a+b+c}"


MANBALAR = [
    ("tuple",           (3, 4, 5)),
    ("list",            [3, 4, 5]),
    ("range",           range(3, 6)),
    ("set",             {3, 4, 5}),
    ("str",             "345"),
    ("generator",       (x for x in [3, 4, 5])),
]

print(f"  {'Manba':<14} {'f(*manba)'}")
print("  " + "─" * 56)
for nom, manba in MANBALAR:
    try:
        natija = uchburchak(*manba)
    except TypeError as x:
        natija = f"❌ {x}"
    print(f"  {nom:<14} {natija}")

print(f"\n  ⚠️ Elementlar soni mos kelishi kerak:")
for manba in [(1, 2), (1, 2, 3, 4)]:
    try:
        uchburchak(*manba)
        natija = "✅"
    except TypeError as x:
        natija = f"❌ {x}"
    print(f"    uchburchak(*{manba}) → {natija}")


print("\n=== 5. ⭐ ** bilan ochish ===")


def ulan(host, port, ssl=False, timeout=30):
    return (f"Ulanish({host}:{port}, ssl={ssl}, timeout={timeout})")


SOZLAMALAR = [
    ("To'liq",      {"host": "db.uz", "port": 5432, "ssl": True, "timeout": 60}),
    ("Qisman",      {"host": "db.uz", "port": 5432}),
    ("Ortiqcha",    {"host": "db.uz", "port": 5432, "yangi": 1}),
    ("Kam",         {"host": "db.uz"}),
    ("Int kalit",   {1: "x"}),
]

print(f"  {'Sozlama':<12} {'Natija'}")
print("  " + "─" * 68)
for nom, s in SOZLAMALAR:
    try:
        natija = ulan(**s)
    except TypeError as x:
        natija = f"❌ TypeError: {x}"
    print(f"  {nom:<12} {natija}")


print("\n=== 6. Birgalikda ===")

print(f"  ulan(*['db.uz', 5432], **{{'ssl': True}})")
print(f"  → {ulan(*['db.uz', 5432], **{'ssl': True})}")

print(f"\n  Konfiguratsiyani qatlamlash:")
STANDART = {"host": "localhost", "port": 5432, "timeout": 30}
FOYDALANUVCHI = {"host": "db.wisar.uz", "ssl": True}

print(f"    STANDART = {STANDART}")
print(f"    FOYDALANUVCHI = {FOYDALANUVCHI}")
print(f"    ulan(**{{**STANDART, **FOYDALANUVCHI}})")
print(f"    → {ulan(**{**STANDART, **FOYDALANUVCHI})}")


print("\n=== 7. Argumentlarni yo'naltirish ===")


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


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


print(f"  orash(1, 2):")
print(f"    → {orash(1, 2)}")

print(f"\n  orash(1, 2, c=30, d=40):")
print(f"    → {orash(1, 2, c=30, d=40)}")

print(f"\n  orash(1, b=2, d=40):")
print(f"    → {orash(1, b=2, d=40)}")

print("""
  ⭐ *args, **kwargs — dekoratorlar va o'rash funksiyalarining asosi.
     5-darsda batafsil.
""")


print("\n=== 8. Qisman qo'llash (partial) ===")

from functools import partial


def kuch(asos, daraja):
    return asos ** daraja


kvadrat = partial(kuch, daraja=2)
kub = partial(kuch, daraja=3)
ikki_darajasi = partial(kuch, 2)

print(f"  kuch(asos, daraja) dan:\n")
print(f"    kvadrat = partial(kuch, daraja=2)")
print(f"    kub = partial(kuch, daraja=3)")
print(f"    ikki_darajasi = partial(kuch, 2)\n")

print(f"    {'x':>4} {'kvadrat':>10} {'kub':>10} {'2^x':>10}")
print("    " + "─" * 38)
for x in [2, 3, 4, 5]:
    print(f"    {x:>4} {kvadrat(x):>10} {kub(x):>10} {ikki_darajasi(x):>10}")

print(f"\n  partial ichida:")
print(f"    kvadrat.func = {kvadrat.func.__name__}")
print(f"    kvadrat.args = {kvadrat.args}")
print(f"    kvadrat.keywords = {kvadrat.keywords}")

Natijaning muhim qismi:

text
=== 2. Xatolar ===
  bol(1)               ❌ TypeError: bol() missing 1 required positional argument: 'b'
  bol(1, 2, 3)         ❌ TypeError: bol() takes 2 positional arguments but 3 were given
  bol(1, a=2)          ❌ TypeError: bol() got multiple values for argument 'a'
  bol(x=1, y=2)        ❌ TypeError: bol() got an unexpected keyword argument 'x'

  bol(a=1, 2):
    ❌ SyntaxError: positional argument follows keyword argument

=== 4. ⭐ * bilan ochish ===
  Manba          f(*manba)
  ────────────────────────────────────────────────────────
  tuple          Uchburchak(3, 4, 5), perimetr=12
  str            Uchburchak(3, 4, 5), perimetr=345

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

Misol 3 — Ko'p parametr va validatsiya

python
"""Ko'p parametrli funksiyalar muammosi va yechimlari."""

from dataclasses import dataclass, field

print("=== 1. ❌ Ko'p pozitsion parametr ===")


def hisobot_yomon(malumot, sarlavha, kenglik, balandlik,
                  ramka, sarlavha_korsatilsinmi, raqamlar,
                  ajratgich, tekislash, rang):
    """10 ta parametr — chaqiruv o'qib bo'lmaydi."""
    return f"Hisobot({sarlavha!r}, {kenglik}×{balandlik}, ...)"


print(f"  Chaqiruv:")
print(f"    hisobot_yomon(d, 'Sotuvlar', 80, 24, True, True, False, '|', 'chap', 'qora')")
print(f"    ↑ 80 nima? 24 nima? True lar nima?\n")

print(f"  Muammolar:")
print(f"    • Tartibni eslash kerak")
print(f"    • Chaqiruv o'qib bo'lmaydi")
print(f"    • Yangi parametr — barcha chaqiruvni buzadi")
print(f"    • Bool argumentlar tushunarsiz")


print("\n=== 2. ✅ Yechim 1: nomli argumentlarni majburiy ===")


def hisobot_nomli(malumot, *, sarlavha, kenglik=80, balandlik=24,
                  ramka=True, raqamlar=False, ajratgich="|",
                  tekislash="chap", rang="qora"):
    """* dan keyingi hammasi FAQAT nomli (6-dars)."""
    return (f"Hisobot({sarlavha!r}, {kenglik}×{balandlik}, "
            f"ramka={ramka}, raqamlar={raqamlar})")


print(f"  def f(malumot, *, sarlavha, kenglik=80, ...):\n")
print(f"  ✅ Chaqiruv:")
natija = hisobot_nomli({}, sarlavha="Sotuvlar", kenglik=100, raqamlar=True)
print(f"    hisobot_nomli(d, sarlavha='Sotuvlar', kenglik=100, raqamlar=True)")
print(f"    → {natija}")

print(f"\n  ❌ Pozitsion — endi mumkin emas:")
try:
    hisobot_nomli({}, "Sotuvlar", 100)
except TypeError as x:
    print(f"    hisobot_nomli(d, 'Sotuvlar', 100) → TypeError: {x}")

print(f"\n  ⭐ Afzalliklari:")
print(f"    • Chaqiruv o'z-o'zini hujjatlaydi")
print(f"    • Yangi parametr qo'shish xavfsiz")
print(f"    • Tartib muhim emas")


print("\n=== 3. ✅ Yechim 2: konfiguratsiya obyekti ===")


@dataclass
class HisobotSozlamalari:
    """Barcha sozlamalar bitta obyektda."""
    kenglik: int = 80
    balandlik: int = 24
    ramka: bool = True
    raqamlar: bool = False
    ajratgich: str = "|"
    tekislash: str = "chap"
    rang: str = "qora"

    def __post_init__(self):
        if self.tekislash not in {"chap", "markaz", "ong"}:
            raise ValueError(f"Noto'g'ri tekislash: {self.tekislash}")
        if not 20 <= self.kenglik <= 200:
            raise ValueError(f"kenglik 20-200 oralig'ida: {self.kenglik}")


def hisobot_obyekt(malumot, sarlavha: str,
                   sozlamalar: HisobotSozlamalari | None = None):
    s = sozlamalar or HisobotSozlamalari()
    return f"Hisobot({sarlavha!r}, {s.kenglik}×{s.balandlik}, ramka={s.ramka})"


print(f"  Sukut sozlamalar bilan:")
print(f"    hisobot_obyekt(d, 'Sotuvlar')")
print(f"    → {hisobot_obyekt({}, 'Sotuvlar')}")

print(f"\n  Maxsus sozlamalar:")
s = HisobotSozlamalari(kenglik=120, raqamlar=True, tekislash="markaz")
print(f"    s = HisobotSozlamalari(kenglik=120, raqamlar=True, tekislash='markaz')")
print(f"    hisobot_obyekt(d, 'Sotuvlar', s)")
print(f"    → {hisobot_obyekt({}, 'Sotuvlar', s)}")

print(f"\n  ⭐ Validatsiya bepul keladi:")
for kwargs in [{"tekislash": "yuqori"}, {"kenglik": 5}]:
    try:
        HisobotSozlamalari(**kwargs)
        natija = "✅"
    except ValueError as x:
        natija = f"❌ {x}"
    print(f"    HisobotSozlamalari(**{kwargs}) → {natija}")

print(f"\n  ⭐ Sozlamalarni qayta ishlatish va o'zgartirish:")
from dataclasses import replace
s2 = replace(s, kenglik=200)
print(f"    replace(s, kenglik=200) → kenglik={s2.kenglik}, "
      f"tekislash={s2.tekislash}")


print("\n=== 4. Argumentlarni tekshirish ===")

print(f"  ⭐ EAFP — Python o'zi aniq xato beradi:\n")


def bol_tekshiruvsiz(a, b):
    return a / b


SINOVLAR = [(10, 2), (10, 0), ("a", 2), (10, "b"), (None, 2)]

for a, b in SINOVLAR:
    try:
        natija = f"✅ {bol_tekshiruvsiz(a, b)}"
    except (TypeError, ZeroDivisionError) as x:
        natija = f"❌ {type(x).__name__}: {x}"
    print(f"    bol({a!r}, {b!r}) → {natija}")

print(f"\n  ✅ Qachon tekshirish KERAK:\n")


def yosh_toifasi(yosh: int) -> str:
    """Tekshiruvsiz xato tushunarsiz bo'lardi."""
    if not isinstance(yosh, int) or isinstance(yosh, bool):
        raise TypeError(f"yosh butun son bo'lishi kerak, {type(yosh).__name__} keldi")
    if not 0 <= yosh <= 150:
        raise ValueError(f"yosh 0-150 oralig'ida bo'lishi kerak, {yosh} keldi")

    if yosh < 13:
        return "bola"
    if yosh < 20:
        return "o'smir"
    if yosh < 60:
        return "kattalar"
    return "keksa"


for yosh in [5, 15, 30, 70, -5, 200, "30", 30.5, True]:
    try:
        natija = f"✅ {yosh_toifasi(yosh)}"
    except (TypeError, ValueError) as x:
        natija = f"❌ {type(x).__name__}: {x}"
    print(f"    yosh_toifasi({yosh!r}) → {natija}")

print("""
  ⭐ Tekshirish kerak:
     • Xato xabari tushunarsiz bo'lsa
     • Xato ancha keyin chiqsa
     • Tashqi kirish (API, foydalanuvchi, fayl)
     • Mantiqiy cheklovlar (oraliq, format)

  ⚠️ Tekshirish KERAK EMAS:
     • Python o'zi aniq xato beradigan holatlar
     • Ichki yordamchi funksiyalar
""")


print("\n=== 5. Tur ko'rsatkichlari tekshirmaydi ===")


def kvadrat(x: int) -> int:
    return x ** 2


SINOVLAR = [5, 2.5, "3", [1, 2], True]

print(f"  def kvadrat(x: int) -> int:\n")
for x in SINOVLAR:
    try:
        natija = f"✅ {kvadrat(x)}"
    except TypeError as e:
        natija = f"❌ {e}"
    print(f"    kvadrat({x!r}) → {natija}")

print(f"""
  ⚠️ Python tur ko'rsatkichlarini TEKSHIRMAYDI.
     '3' ** 2 xato beradi, lekin 2.5 va True ishlaydi.

  ⭐ Tekshirish uchun:
     • mypy / pyright — statik (yozish paytida)
     • pydantic — ish vaqtida
     • beartype — dekorator bilan

  14-darsda batafsil.
""")


print("\n=== 6. Parametrlar sonini kamaytirish ===")

print("""
  Belgilar va yechimlar:

  ┌────────────────────────────┬───────────────────────────────────┐
  │ Muammo                     │ Yechim                            │
  ├────────────────────────────┼───────────────────────────────────┤
  │ 5+ parametr                │ * bilan nomli qilish              │
  │ Bog'liq parametrlar guruhi │ dataclass                         │
  │ Bool argumentlar ko'p      │ Enum yoki alohida funksiyalar     │
  │ Ba'zi parametr kamdan-kam  │ **kwargs + sukut lug'at           │
  │ Har xil ish rejimi         │ Alohida funksiyalar               │
  │ Ko'p bog'liq holat         │ Sinf                              │
  └────────────────────────────┴───────────────────────────────────┘
""")

print(f"  Bool argumentlar o'rniga Enum:\n")

from enum import Enum


class Tekislash(Enum):
    CHAP = "chap"
    MARKAZ = "markaz"
    ONG = "ong"


def matn_chiqar(matn: str, kenglik: int, tekislash: Tekislash):
    if tekislash is Tekislash.CHAP:
        return matn.ljust(kenglik, ".")
    if tekislash is Tekislash.ONG:
        return matn.rjust(kenglik, ".")
    return matn.center(kenglik, ".")


print(f"    ❌ matn_chiqar('x', 20, True, False)")
print(f"    ✅ matn_chiqar('x', 20, Tekislash.MARKAZ)\n")
for t in Tekislash:
    print(f"      {t.name:<8} {matn_chiqar('SALOM', 20, t)}")

Natijaning muhim qismi:

text
=== 2. ✅ Yechim 1: nomli argumentlarni majburiy ===
  ❌ Pozitsion — endi mumkin emas:
    hisobot_nomli(d, 'Sotuvlar', 100) → TypeError: hisobot_nomli() takes 1
    positional argument but 3 were given

=== 4. Argumentlarni tekshirish ===
    bol(10, 2) → ✅ 5.0
    bol(10, 0) → ❌ ZeroDivisionError: division by zero
    bol('a', 2) → ❌ TypeError: unsupported operand type(s) for /: 'str' and 'int'

    yosh_toifasi(-5) → ❌ ValueError: yosh 0-150 oralig'ida bo'lishi kerak, -5 keldi
    yosh_toifasi(True) → ❌ TypeError: yosh butun son bo'lishi kerak, bool keldi

=== 5. Tur ko'rsatkichlari tekshirmaydi ===
    kvadrat(5) → ✅ 25
    kvadrat(2.5) → ✅ 6.25
    kvadrat('3') → ❌ unsupported operand type(s)
    kvadrat(True) → ✅ 1

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

Misol 4 — Amaliy: ma'lumot qayta ishlash quvuri

python
"""Argumentlarni to'g'ri boshqarish — real vazifa."""

import copy
from dataclasses import dataclass, field, replace
from typing import Callable

print("=== Yozuvlar qayta ishlash tizimi ===\n")

XOM_YOZUVLAR = [
    {"id": 1, "ism": "  Aziz  ", "yosh": "30", "bolim": "IT", "maosh": 7_000_000},
    {"id": 2, "ism": "bobur", "yosh": 25, "bolim": "hr", "maosh": "5000000"},
    {"id": 3, "ism": "AZIZA", "yosh": "notogri", "bolim": "IT", "maosh": 8_000_000},
    {"id": 4, "ism": "", "yosh": 28, "bolim": "Moliya", "maosh": 6_000_000},
    {"id": 5, "ism": "Eldor", "yosh": 42, "bolim": "IT", "maosh": None},
]

print("=== 1. ❌ Argumentni buzuvchi funksiya ===")


def tozala_yomon(yozuvlar: list[dict]) -> list[dict]:
    """⚠️ Asl ro'yxatni VA ichidagi lug'atlarni o'zgartiradi."""
    for y in yozuvlar:
        if isinstance(y.get("ism"), str):
            y["ism"] = y["ism"].strip().title()
    return yozuvlar


asl_nusxa = copy.deepcopy(XOM_YOZUVLAR)
natija = tozala_yomon(XOM_YOZUVLAR)

print(f"  Chaqiruvdan keyin:")
print(f"    XOM_YOZUVLAR[0]['ism'] = {XOM_YOZUVLAR[0]['ism']!r}   ⚠️ O'ZGARDI")
print(f"    natija is XOM_YOZUVLAR = {natija is XOM_YOZUVLAR}   ⚠️")

XOM_YOZUVLAR[:] = asl_nusxa                 # tiklash


print("\n=== 2. ✅ Xavfsiz funksiyalar ===")


def ismni_tozala(yozuv: dict) -> dict:
    """Yangi lug'at qaytaradi."""
    ism = yozuv.get("ism", "")
    if not isinstance(ism, str):
        return {**yozuv, "ism": ""}
    return {**yozuv, "ism": ism.strip().title()}


def songa_aylantir(yozuv: dict, maydon: str, sukut=None) -> dict:
    """Maydonni int ga aylantiradi."""
    qiymat = yozuv.get(maydon)
    if isinstance(qiymat, int) and not isinstance(qiymat, bool):
        return dict(yozuv)
    if isinstance(qiymat, str) and qiymat.lstrip("-").isdigit():
        return {**yozuv, maydon: int(qiymat)}
    return {**yozuv, maydon: sukut}


def bolimni_normalla(yozuv: dict) -> dict:
    """Bo'lim nomini standartlashtiradi."""
    NORMAL = {"it": "IT", "hr": "HR", "moliya": "Moliya"}
    bolim = str(yozuv.get("bolim", "")).lower()
    return {**yozuv, "bolim": NORMAL.get(bolim, yozuv.get("bolim", ""))}


def togrimi(yozuv: dict) -> bool:
    """Yozuv to'liq va to'g'rimi."""
    return bool(
        yozuv.get("ism")
        and isinstance(yozuv.get("yosh"), int)
        and isinstance(yozuv.get("maosh"), int)
        and yozuv.get("bolim")
    )


print(f"  Bosqichma-bosqich (birinchi yozuv):\n")
y = XOM_YOZUVLAR[0]
print(f"    Asl:                {y}")
y1 = ismni_tozala(y)
print(f"    ismni_tozala:       {y1}")
y2 = songa_aylantir(y1, "yosh")
print(f"    songa_aylantir:     {y2}")
y3 = bolimni_normalla(y2)
print(f"    bolimni_normalla:   {y3}")
print(f"\n    XOM_YOZUVLAR[0] o'zgarmadi: {XOM_YOZUVLAR[0]['ism']!r}   ✅")


print("\n=== 3. Quvur ===")


def quvur(yozuvlar: list[dict], *bosqichlar: Callable) -> list[dict]:
    """Har bosqichni ketma-ket qo'llaydi. Asl o'zgarmaydi."""
    natija = yozuvlar
    for bosqich in bosqichlar:
        natija = [bosqich(y) for y in natija]
    return natija


def yosh_songa(y):
    return songa_aylantir(y, "yosh")


def maosh_songa(y):
    return songa_aylantir(y, "maosh")


qayta_ishlangan = quvur(
    XOM_YOZUVLAR,
    ismni_tozala,
    yosh_songa,
    maosh_songa,
    bolimni_normalla,
)

print(f"  quvur(XOM_YOZUVLAR, ismni_tozala, yosh_songa, maosh_songa, bolimni_normalla)\n")
print(f"  {'ID':>3} {'Ism':<10} {'Yosh':>6} {'Bo`lim':<8} {'Maosh':>12} {'To`g`ri'}")
print("  " + "─" * 56)
for y in qayta_ishlangan:
    yosh = y["yosh"] if y["yosh"] is not None else "—"
    maosh = f"{y['maosh']:,}" if y["maosh"] is not None else "—"
    belgi = "✅" if togrimi(y) else "❌"
    print(f"  {y['id']:>3} {y['ism'] or '(bo`sh)':<10} {str(yosh):>6} "
          f"{y['bolim']:<8} {maosh:>12} {belgi:>6}")

print(f"\n  Asl ma'lumot o'zgarmadi:")
print(f"    XOM_YOZUVLAR[0]['ism'] = {XOM_YOZUVLAR[0]['ism']!r}   ✅")


print("\n=== 4. Ko'p parametrli funksiyani qayta loyihalash ===")

print(f"  ❌ Asl:")
print(f"""
    def hisobot(yozuvlar, sarlavha, guruh_maydoni, saralash_maydoni,
                kamayish, chegara, jami_korsatilsinmi, foizlar,
                kenglik, ajratgich):
""")


@dataclass(frozen=True)
class HisobotSozlamalari:
    """✅ Barcha sozlamalar bitta o'zgarmas obyektda."""
    sarlavha: str = "HISOBOT"
    guruh_maydoni: str = "bolim"
    saralash_maydoni: str = "maosh"
    kamayish: bool = True
    chegara: int | None = None
    jami: bool = True
    foizlar: bool = False
    kenglik: int = 56

    def __post_init__(self):
        if self.chegara is not None and self.chegara < 1:
            raise ValueError(f"chegara musbat bo'lishi kerak: {self.chegara}")
        if not 20 <= self.kenglik <= 200:
            raise ValueError(f"kenglik 20-200: {self.kenglik}")


def hisobot(yozuvlar: list[dict],
            sozlamalar: HisobotSozlamalari | None = None) -> str:
    """✅ Ikkita parametr, biri ixtiyoriy."""
    s = sozlamalar or HisobotSozlamalari()

    toza = [y for y in yozuvlar if togrimi(y)]
    if not toza:
        return "Ma'lumot yo'q"

    guruhlar: dict[str, list[dict]] = {}
    for y in toza:
        guruhlar.setdefault(y[s.guruh_maydoni], []).append(y)

    qatorlar = [f"┌─ {s.sarlavha}", "│"]

    jami_hammasi = sum(y[s.saralash_maydoni] for y in toza)

    tartib = sorted(
        guruhlar.items(),
        key=lambda kv: sum(y[s.saralash_maydoni] for y in kv[1]),
        reverse=s.kamayish,
    )
    if s.chegara:
        tartib = tartib[:s.chegara]

    for guruh, xodimlar in tartib:
        guruh_jami = sum(y[s.saralash_maydoni] for y in xodimlar)
        qator = f"│  {guruh:<10} {len(xodimlar):>2} xodim  {guruh_jami:>14,}"
        if s.foizlar:
            qator += f"  ({guruh_jami / jami_hammasi:>5.1%})"
        qatorlar.append(qator)

    if s.jami:
        qatorlar.append("│")
        qatorlar.append(f"│  {'JAMI':<10} {len(toza):>2} xodim  {jami_hammasi:>14,}")

    qatorlar.append("└─")
    return "\n".join("  " + q for q in qatorlar)


print(f"  ✅ Yangi:")
print(f"    def hisobot(yozuvlar, sozlamalar=None):\n")

print(f"  Sukut sozlamalar bilan:")
print(hisobot(qayta_ishlangan))

print(f"\n  Maxsus sozlamalar bilan:")
s = HisobotSozlamalari(sarlavha="BO'LIMLAR BO'YICHA", foizlar=True, chegara=2)
print(hisobot(qayta_ishlangan, s))

print(f"\n  Sozlamalarni o'zgartirish (replace):")
s2 = replace(s, sarlavha="TO'LIQ", chegara=None, kamayish=False)
print(hisobot(qayta_ishlangan, s2))


print("\n\n=== 5. Validatsiya ===")

NOTOGRI = [
    {"chegara": 0},
    {"chegara": -5},
    {"kenglik": 5},
    {"kenglik": 500},
]

print(f"  HisobotSozlamalari validatsiyasi:\n")
for kwargs in NOTOGRI:
    try:
        HisobotSozlamalari(**kwargs)
        natija = "✅"
    except ValueError as x:
        natija = f"❌ {x}"
    print(f"    {str(kwargs):<24} {natija}")


print("\n=== 6. Xulosa: uchta qoida ===")

print("""
  1️⃣ Argumentni o'zgartirmang

     ❌ def f(r): r.append(x); return r
     ✅ def f(r): return [*r, x]
     ✅ def f(r) -> None: r.append(x)        (ataylab, None qaytaradi)

  2️⃣ 4+ parametr bo'lsa — nomli yoki obyekt

     ❌ def f(a, b, c, d, e, f, g): ...
     ✅ def f(a, *, b=1, c=2, ...): ...
     ✅ def f(a, sozlamalar: Sozlamalar): ...

  3️⃣ Tekshirish — faqat kerak bo'lganda

     ❌ Har argument uchun isinstance
     ✅ Tashqi kirish, tushunarsiz xato, kech chiqadigan xato
     ✅ Tur ko'rsatkichlari + mypy
""")

Natijaning muhim qismi:

text
=== 3. Quvur ===
   ID Ism          Yosh Bo`lim         Maosh To`g`ri
  ────────────────────────────────────────────────────────
    1 Aziz           30 IT         7,000,000     ✅
    2 Bobur          25 HR         5,000,000     ✅
    3 Aziza           — IT         8,000,000     ❌
    4 (bo`sh)        28 Moliya     6,000,000     ❌
    5 Eldor          42 IT                 —     ❌

  Asl ma'lumot o'zgarmadi:
    XOM_YOZUVLAR[0]['ism'] = '  Aziz  '   ✅

=== 4. Ko'p parametrli funksiyani qayta loyihalash ===
  Maxsus sozlamalar bilan:
  ┌─ BO'LIMLAR BO'YICHA
  │
  │  IT          1 xodim       7,000,000  (58.3%)
  │  HR          1 xodim       5,000,000  (41.7%)
  │
  │  JAMI        2 xodim      12,000,000
  └─

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


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

Noto'g'ri fikr To'g'risi
"Python qiymat bo'yicha uzatadi" Obyektga havolani qiymat bo'yicha
"Python havola bo'yicha uzatadi" x = yangi tashqarida ko'rinmaydi
"O'zgaruvchan argument har doim o'zgaradi" Faqat obyekt o'zgartirilsa, qayta bog'lansa yo'q
"x += y har doim bir xil" list — joyida, int — yangi obyekt
"d.copy() argumentni himoyalaydi" Sayoz — ichma-ich uchun yetarli emas
"Tur ko'rsatkichlari tekshiradi" Faqat hujjat. mypy kerak
"Har argumentni tekshirish kerak" EAFP — Python o'zi aniq xato beradi
"Ko'p parametr — normal" 4+ bo'lsa qayta loyihalang
"Nomli argument sekinroq" Farq sezilmas darajada

6. Keng tarqalgan xatolar va yechimlari

1. Argumentni jimgina o'zgartirish

python
def qosh(r, x):
    r.append(x); return r       # ⚠️ chaqiruvchi ajablanadi

def qosh(r, x):
    return [*r, x]              # ✅

2. Sayoz nusxaga ishonish

python
def f(d):
    d = dict(d)                 # ⚠️ ichma-ich bo'lsa yetarli emas
    d["ichki"]["x"] = 1

def f(d):
    d = copy.deepcopy(d)        # ✅

3. Nomli argument pozitsiondan oldin

python
f(a=1, 2)                       # ❌ SyntaxError
f(1, b=2)                       # ✅

4. Bir parametrga ikki qiymat

python
f(1, a=2)                       # ❌ multiple values for argument 'a'

5. Ko'p pozitsion parametr

python
def f(a, b, c, d, e, g): ...    # ❌ chaqiruv o'qib bo'lmaydi
def f(a, *, b, c, d=1): ...     # ✅

6. Bool argumentlar

python
f(x, True, False, True)         # ❌ nima nima?
f(x, faol=True, korinmas=False) # ✅

7. Tur ko'rsatkichlariga ishonish

python
def f(x: int): return x * 2
f("a")                          # ⚠️ "aa" — xato yo'q!

8. ** da noto'g'ri kalitlar

python
f(**{"noma'lum": 1})            # ❌ unexpected keyword argument
f(**{1: "a"})                   # ❌ keywords must be strings

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 7.3-dars: sukut qiymatlar va o'zgaruvchan sukut tuzog'i
  • 7.4-dars: nomli argumentlar batafsil
  • 7.5-dars: *args, **kwargs
  • 7.6-dars: faqat pozitsion va faqat nomli
  • 6.1, 6.18-darslar (o'tilgan): yorliq modeli, nusxa olish
  • 6.2-dars (o'tilgan): None qaytaruvchi metodlar kelishuvi
  • 8-qism: metodlar va self
  • 9-qism: TypeError, ValueError

8. Eng yaxshi amaliyotlar

  1. Argumentni o'zgartirmang. Yangi obyekt qaytaring yoki ichkarida nusxa oling.

  2. Ataylab o'zgartirsangiz — None qaytaring va hujjatda yozing.

  3. 4+ parametr — nomli argumentlar yoki dataclass.

  4. Bool argumentlarni doim nomli uzating. f(x, faol=True).

  5. Tekshirishni faqat kerak bo'lganda. EAFP — Python o'zi xato beradi.

  6. Tashqi kirishni doim tekshiring. API, foydalanuvchi, fayl.

  7. Ichma-ich tuzilma uchun deepcopy. Sayoz nusxa yetarli emas.

  8. Tur ko'rsatkichlari + mypy. Hujjat va statik tekshiruv birga.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
def f1(x): x = 99
def f2(x): x.append(99)
def f3(x): x += [99]
def f4(x): x += 1
def f5(x): x[0] = 99
def f6(x): x = x + [99]

1.  a = 1; f1(a); print(a)
2.  a = [1]; f2(a); print(a)
3.  a = [1]; f3(a); print(a)
4.  a = 1; f4(a); print(a)
5.  a = [1]; f5(a); print(a)
6.  a = [1]; f6(a); print(a)
7.  a = (1,); f3(a); print(a)
8.  a = {"x": 1}; f5(a); print(a)
9.  def g(a, b): return a - b
    print(g(b=1, a=10))
10. def h(*args): return args
    print(h(*[1,2], *(3,)))
11. def k(a, b=2): return a, b
    print(k(**{"a": 1, "b": 3}))
12. def m(a): return a
    print(m(*[1]))
Javoblar
  1. 1 — qayta bog'lash lokal
  2. [1, 99] — obyekt o'zgardi
  3. [1, 99] — list.__iadd__ joyida
  4. 1 — int yangi obyekt
  5. [99] — element almashtirildi
  6. [1] — x + [99] yangi obyekt
  7. TypeError — tuple o'zgarmas
  8. {'x': 1, 0: 99} — lug'atda x[0] = 99 yangi 0 kalitini yaratadi (ro'yxatdan farqli)
  9. 9
  10. (1, 2, 3)
  11. (1, 3)
  12. 1

Vazifa 2: Xatolarni tuzating

python
1.  def qosh(r, x): r.append(x); return r
2.  def f(d): d = dict(d); d["a"]["b"] = 1
3.  f(a=1, 2)
4.  def f(a, b, c, d, e, g, h): ...
5.  yarat_tugma("OK", 100, 30, True, False)
6.  def f(x: int) -> int: return x * 2
    # foydalanuvchi kiritgan qiymat uzatiladi
7.  def sarala(r): r.sort(); return r
8.  f(**{"noma'lum": 1})
Javoblar
python
1.  def qosh(r, x): return [*r, x]
2.  d = copy.deepcopy(d)
3.  f(1, a=2)  yoki f(a=1, b=2)
4.  def f(a, *, b, c, d=1, e=2, g=3, h=4): ... yoki dataclass
5.  yarat_tugma("OK", kenglik=100, balandlik=30, faol=True, korinmas=False)
6.  Tekshiring: if not isinstance(x, int): raise TypeError(...)
7.  def sarala(r): return sorted(r)   # yoki -> None qiling
8.  Parametr nomlarini tekshiring

Vazifa 3: Xavfsiz kutubxona

Funksiyalar yozing (hech biri argumentni o'zgartirmasin):

  1. qosh(r, x), ochir(r, x), almashtir(r, i, x)
  2. birlashtir(*royxatlar), oraliq(r, a, b)
  3. guruhla(r, kalit_f) — lug'at qaytarsin
  4. yangila(d, **ozgarishlar) — chuqur birlashtirish
  5. Har biri uchun test: asl o'zgarmaganini tekshiring
  6. -> None versiyalarini ham yozing (joyida)

Vazifa 4: Uzatish tahlilchisi

Dastur yozing:

  1. Funksiya argumentni o'zgartiradimi — aniqlasin
  2. id() va deepcopy bilan solishtirish orqali
  3. Qaysi maydonlar o'zgarganini ko'rsatsin
  4. Dekorator sifatida: @ozgartirmasligini_tekshir
  5. Ogohlantirish yoki xato bersin

Vazifa 5: Konfiguratsiya tizimi

Ko'p parametrli funksiyani qayta loyihalang:

  1. dataclass(frozen=True) sozlamalar
  2. __post_init__ da validatsiya
  3. replace() bilan o'zgartirish
  4. Fayl/muhitdan yuklash
  5. Sukut qiymatlar bilan birlashtirish
  6. to_dict() / from_dict()

Vazifa 6: Validatsiya dekoratori

Yozing:

python
@tekshir(yosh=(int, 0, 150), ism=(str, 1, 50))
def yarat_foydalanuvchi(ism, yosh): ...
  1. Tur tekshiruvi
  2. Oraliq/uzunlik tekshiruvi
  3. Aniq xato xabarlari
  4. Tur ko'rsatkichlaridan avtomatik olish
  5. pydantic bilan solishtirish

Vazifa 7: O'ylash

Nega Python "qiymat bo'yicha" yoki "havola bo'yicha" emas, balki uchinchi modelni tanladi?

Javob

Chunki Pythonda "o'zgaruvchi" — quti emas, yorliq.

Boshqa tillarda:

C — qiymat bo'yicha:

c
void f(int x) { x = 99; }
int a = 1;
f(a);                   // a == 1 — x NUSXA

O'zgaruvchi — xotiradagi quti. Uzatishda quti nusxalanadi.

C++ — havola bo'yicha ham mumkin:

cpp
void f(int& x) { x = 99; }
int a = 1;
f(a);                   // a == 99 — x aslining ALIASI

Pythonda quti yo'q:

python
a = 1

Bu — "a qutisiga 1 solindi" emas, balki "1 obyektiga a yorlig'i osildi" (6.1-dars).

a ──→ [1]

Uzatishda nima bo'ladi:

python
def f(x): ...
f(a)

x — shu obyektga yangi yorliq:

a ──┐
    ├──→ [1]
x ──┘

Bu:

  • "qiymat bo'yicha" emas — obyekt nusxalanmadi
  • "havola bo'yicha" emas — x = 99 a ni o'zgartirmaydi (x a ning aliasi emas)

Bu model nima deyiladi:

  • Call by object reference (Python hujjatlarida)
  • Call by sharing (Barbara Liskov, 1974)
  • Call by object (CLU tili)

Bir xil model: Java (obyektlar uchun), Ruby, JavaScript (obyektlar uchun), Smalltalk.

Nega bu tanlandi:

1. Model izchil.

Pythonda hamma narsa obyekt — int, str, funksiya, sinf, modul. Va o'zgaruvchi har doim yorliq. Funksiya chaqiruvi — shunchaki yangi yorliq bog'lash:

python
x = a           # yorliq bog'lash
f(a)            # parametr uchun yorliq bog'lash — BIR XIL narsa

Bir qoida — barcha holat uchun.

2. Nusxalash qimmat bo'lardi.

Agar Python "qiymat bo'yicha" uzatsa:

python
katta = list(range(10_000_000))
f(katta)                        # ⚠️ 400 MB nusxa!

Har chaqiruvda nusxa — mumkin emas.

3. "Havola bo'yicha" xavfli bo'lardi.

python
def f(x):
    x = [99]                    # agar havola bo'yicha bo'lsa:
a = [1]
f(a)
print(a)                        # [99]?  ⚠️ juda chalkash

Funksiya chaqiruvchining o'zgaruvchisini qayta bog'lay olardi. Bu — kodni kuzatishni juda qiyinlashtiradi.

4. Amalda kerakli ikkala xatti-harakat ham bor:

python
def f(x): x.append(1)           # "havola bo'yicha" kabi
def f(x): x = [1]               # "qiymat bo'yicha" kabi

Farq — obyektning o'zgaruvchanligida, uzatish mexanizmida emas.

Chalkashlik manbai:

Ko'pchilik "o'zgaruvchan obyekt havola bo'yicha, o'zgarmas qiymat bo'yicha uzatiladi" deb o'ylaydi. Bu — noto'g'ri:

python
def f(x):
    x = [99]

a = [1]                         # O'ZGARUVCHAN
f(a)
print(a)                        # [1] — "havola bo'yicha" bo'lsa [99] bo'lardi

Uzatish har doim bir xil. Farq — funksiya ichida nima qilinishida:

  • Obyektni o'zgartirish (x.append, x[0] = ) → tashqarida ko'rinadi
  • Yorliqni qayta bog'lash (x = ) → lokal

Amaliy natija:

Bitta savol yetarli: "obyekt o'zgartirildimi yoki yorliq qayta bog'landimi?"

python
x.metod()       obyekt      → tashqarida ko'rinadi
x[i] = y        obyekt      → tashqarida
x += y          list: obyekt, int: yorliq
x = y           yorliq      → lokal

Xulosa: Python "uchinchi model" ni ataylab tanlamagan — u yorliq modelining tabiiy oqibati. Agar o'zgaruvchi yorliq bo'lsa, funksiya parametri ham yorliq bo'lishi kerak. Boshqa variant izchil bo'lmasdi.

Nimani mustahkamlaydi: 2.2, 2.3-bo'limlar.


Xulosa

Bu darsda argument uzatish mexanizmini o'rgandik.

Eng muhim uch fikr:

  1. Python obyektga havolani qiymat bo'yicha uzatadi. Parametr — asl obyektga yangi yorliq. Shuning uchun x.append(1) tashqarida ko'rinadi, x = [1] esa yo'q. Farq — uzatish mexanizmida emas, funksiya ichida nima qilinishida.

  2. Argumentni o'zgartirmang. Yangi obyekt qaytaring (return [*r, x]), yoki ataylab joyida o'zgartirib None qaytaring, yoki ichkarida nusxa oling. Ichma-ich tuzilma uchun deepcopy kerak.

  3. 4+ parametr — qayta loyihalang. * bilan nomli argumentlarni majburiy qiling, dataclass sozlamalar obyekti yarating, yoki funksiyani bo'ling. Bool argumentlarni doim nom bilan uzating.

Keyingi darsda sukut qiymatlarni va Pythonning eng mashhur tuzog'ini — o'zgaruvchan sukut argumentni — ko'ramiz.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
7.2-dars: Argument va parametr — IlmHamroh