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

7.4-dars: Nomli argumentlar

7-QISM — FUNKSIYALAR · 4-dars


1. Kirish va motivatsiya

Ikki chaqiruv, bir xil natija:

python
yarat_oyna("Hisobot", 800, 600, True, False, True, None, 3)
python
yarat_oyna(
    sarlavha="Hisobot",
    kenglik=800,
    balandlik=600,
    korinadigan=True,
    modal=False,
    ozgartirilsin=True,
    ota=None,
    ramka_qalinligi=3,
)

Birinchisini o'qib bo'lmaydi. True, False, True nimani anglatadi? 3 nima?

Ikkinchisi uzunroq, lekin o'z-o'zini hujjatlaydi. Va parametr tartibi o'zgarsa ham buzilmaydi.

Lekin nomli argumentlarning o'z qoidalari bor:

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

f(1, 2, c=3)                # ✅
f(a=1, 2, 3)                # ❌ SyntaxError
f(1, a=2)                   # ❌ TypeError — a ikki marta
f(1, 2, 3, d=4)             # ❌ TypeError — d yo'q

Va nozik holatlar:

python
def f(**kwargs): ...
f(**{"1-kalit": 1})         # ✅ ishlaydi
f(**{1: "a"})               # ❌ TypeError

Bu darsda:

  • Nomli argumentlar semantikasi va qoidalari
  • Qachon ishlatish — o'qilish qoidalari
  • API dizayni — parametr tartibi va evolyutsiyasi
  • ** bilan ochish nozikliklari
  • Nomlarni o'zgartirish — orqaga moslik
  • Tezlik va inspect bilan tahlil

2. Nazariya — chuqur tushuntirish

2.1. Semantika va qoidalar

python
def f(a, b, c=3):
    return a, b, c

To'rt shakl:

python
f(1, 2)                     # pozitsion
f(1, 2, 3)                  # pozitsion
f(1, b=2)                   # aralash
f(a=1, b=2, c=3)            # to'liq nomli
f(c=3, a=1, b=2)            # tartib erkin

Uchta qoida:

1. Pozitsion argumentlar nomlidan OLDIN:

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

Bu — sintaksis xatosi, ish vaqtida emas.

2. Har parametr bir marta:

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

3. Nom mavjud bo'lishi kerak:

python
f(1, 2, d=4)                # ❌ TypeError: got an unexpected keyword argument 'd'

Nomli argumentda tartib muhim emas:

python
f(c=3, b=2, a=1)            # ✅ (1, 2, 3)

Lekin hisoblash tartibi — yozilish tartibida:

python
f(c=birinchi(), a=ikkinchi())       # birinchi() avval chaqiriladi

2.2. Qachon nomli argument ishlatish

1. Bool argumentlar — DOIM nomli:

python
sarala(r, True)                     # ❌ True nima?
sarala(r, reverse=True)             # ✅

f(matn, True, False, True)          # ❌ o'qib bo'lmaydi
f(matn, qatiy=True, hisobga=False, tozala=True)     # ✅

Bu — eng muhim qoida. Bool argument nomsiz — deyarli har doim xato.

2. Ikkitadan ko'p bir xil turdagi argument:

python
kesim(matn, 0, 10)                  # ⚠️ 0 va 10 nima?
kesim(matn, boshi=0, oxiri=10)      # ✅

masofa(1, 2, 3, 4)                  # ⚠️
masofa(x1=1, y1=2, x2=3, y2=4)      # ✅

3. Sukut qiymatli parametrlar:

python
ochish(yol, "r", "utf-8")           # ⚠️ ikkinchi "utf-8" nima?
ochish(yol, kodlash="utf-8")        # ✅

4. Ma'nosi kontekstsiz tushunarsiz:

python
qayta_urin(f, 3, 5)                 # ⚠️ 3 nima, 5 nima?
qayta_urin(f, urinishlar=3, kutish=5)   # ✅

5. Kelajakda parametr qo'shilishi mumkin:

python
# v1
def f(a, b): ...
f(1, 2)

# v2 — parametr O'RTAGA qo'shildi
def f(a, yangi, b): ...
f(1, 2)                             # ⚠️ endi b o'rniga yangi ga tushdi!

# Nomli bilan xavfsiz
f(a=1, b=2)                         # ✅ har doim to'g'ri

Qachon pozitsion yetarli:

python
len(r)                              # ✅ bitta aniq argument
maks(a, b)                          # ✅ ma'no ravshan
qosh(1, 2)                          # ✅
d[kalit]                            # ✅
r.append(x)                         # ✅

Amaliy qoida: agar chaqiruvni o'qib, argument nima ekanini funksiya ta'rifiga qaramasdan aytib bo'lmasa — nom bilan yozing.

2.3. API dizayni

Parametr tartibi — muhim va o'zgartirilmaydigan:

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

Bu tartib — ochiq shartnoma. Uni o'zgartirish barcha pozitsion chaqiruvni buzadi.

Xavfsiz evolyutsiya:

python
# ✅ Yangi parametrni OXIRIGA, sukut bilan
def f(a, b, c=3): ...
def f(a, b, c=3, d=4): ...

# ✅ Yoki * dan keyin (6-dars)
def f(a, b, *, c=3, d=4): ...

# ❌ O'rtaga qo'shish
def f(a, yangi, b): ...             # barcha chaqiruv buziladi

# ❌ Tartibni o'zgartirish
def f(b, a): ...                    # jimgina noto'g'ri natija!

Parametr nomini o'zgartirish — ham buzuvchi:

python
# v1
def f(royxat): ...
f(royxat=[1, 2])                    # ✅

# v2 — nom o'zgardi
def f(elementlar): ...
f(royxat=[1, 2])                    # ❌ TypeError

Shuning uchun parametr nomlari ham ochiq API.

Himoya — faqat pozitsion (6-dars):

python
def f(royxat, /):                   # nom yopiq — o'zgartirish xavfsiz
    ...

Deprecation naqshi:

python
def f(elementlar=None, *, royxat=None):
    """royxat — eskirgan, elementlar ishlating."""
    if royxat is not None:
        import warnings
        warnings.warn(
            "royxat eskirgan, elementlar ishlating",
            DeprecationWarning, stacklevel=2,
        )
        elementlar = royxat
    ...

2.4. ** bilan ochish nozikliklari

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

f(**{"a": 1, "b": 2})               # ✅
f(1, **{"b": 2})                    # ✅ aralash
f(**{"a": 1}, **{"b": 2})           # ✅ ikki lug'at (3.5+)

Takrorlangan kalit:

python
f(**{"a": 1}, **{"a": 2})           # ❌ TypeError: got multiple values for keyword argument 'a'
f(a=1, **{"a": 2})                  # ❌ bir xil

Kalitlar satr bo'lishi kerak:

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

Lekin identifikator bo'lishi SHART EMAS (agar **kwargs bo'lsa):

python
def g(**kwargs): return kwargs

g(**{"1-kalit": 1, "bo'sh joy": 2})     # ✅ {'1-kalit': 1, "bo'sh joy": 2}
g(**{"class": 1})                       # ✅ kalit so'z ham

Chunki **kwargs — oddiy lug'at, uning kalitlariga cheklov yo'q.

To'g'ridan-to'g'ri yozib bo'lmaydi:

python
g(1-kalit=1)                        # ❌ SyntaxError
g(class=1)                          # ❌ SyntaxError
g(**{"class": 1})                   # ✅

Lug'atlarni birlashtirish:

python
STANDART = {"host": "localhost", "port": 5432}
FOYDALANUVCHI = {"host": "db.uz"}

ulan(**STANDART, **FOYDALANUVCHI)       # ❌ host ikki marta!
ulan(**{**STANDART, **FOYDALANUVCHI})   # ✅
ulan(**(STANDART | FOYDALANUVCHI))      # ✅ 3.9+

Filtrlash — faqat mos kalitlarni uzatish:

python
import inspect

def xavfsiz_chaqir(f, **kwargs):
    """Faqat f qabul qiladigan argumentlarni uzatadi."""
    sig = inspect.signature(f)
    if any(p.kind is p.VAR_KEYWORD for p in sig.parameters.values()):
        return f(**kwargs)          # **kwargs bor — hammasini
    mos = {k: v for k, v in kwargs.items() if k in sig.parameters}
    return f(**mos)

2.5. Nomli argumentlar va *args

python
def f(a, b, *args, c=3, **kwargs):
    return a, b, args, c, kwargs

*args dan keyingi parametrlar — FAQAT nomli:

python
f(1, 2, 3, 4)                       # a=1, b=2, args=(3,4), c=3
f(1, 2, 3, 4, 5)                    # c ga hech qachon pozitsion tushmaydi
f(1, 2, 3, c=30)                    # ✅ c=30

Bu — 5 va 6-darslarda batafsil.

Tartib qoidasi:

python
def f(pozitsion, /, oddiy, *args, faqat_nomli, **kwargs):
    #    ↑ faqat pozitsion  ↑ ikkalasi  ↑ qolgan pozitsion
    #                                    ↑ faqat nomli  ↑ qolgan nomli

To'liq shakl (6-dars):

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

2.6. Tezlik

Nomli argumentlar biroz sekinroq — nom bo'yicha qidiruv kerak:

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

f(1, 2, 3)                  # ~60 ns
f(a=1, b=2, c=3)            # ~85 ns   (~40% sekinroq)
f(**{"a": 1, "b": 2, "c": 3})   # ~130 ns

Bu — mikro-farq. Funksiya tanasi har doim bundan ko'p vaqt oladi.

Qachon muhim: juda tor sikllarda (millionlab chaqiruv), masalan sorted(key=...) ichida.

Amaliy tavsiya: o'qilishni tanlang. Tezlik faqat profillash muammoni ko'rsatgandan keyin.

CPython optimallashtirishi:

Python 3.11+ da CALL_FUNCTION_KW va adaptiv bytecode nomli chaqiruvni tezlashtirdi. Farq avvalgidan kichikroq.

2.7. inspect bilan tahlil

python
import inspect

def f(a, b=2, *args, c, d=4, **kwargs): ...

sig = inspect.signature(f)
print(sig)                  # (a, b=2, *args, c, d=4, **kwargs)

for nom, p in sig.parameters.items():
    print(nom, p.kind.name, p.default)
text
a POSITIONAL_OR_KEYWORD <empty>
b POSITIONAL_OR_KEYWORD 2
args VAR_POSITIONAL <empty>
c KEYWORD_ONLY <empty>
d KEYWORD_ONLY 4
kwargs VAR_KEYWORD <empty>

Beshta kind:

Kind Ma'nosi Sintaksis
POSITIONAL_ONLY Faqat pozitsion / dan oldin
POSITIONAL_OR_KEYWORD Ikkalasi ham Oddiy
VAR_POSITIONAL Qolgan pozitsion *args
KEYWORD_ONLY Faqat nomli * dan keyin
VAR_KEYWORD Qolgan nomli **kwargs

Argumentlarni bog'lash:

python
bound = sig.bind(1, c=3)
bound.apply_defaults()
print(bound.arguments)      # {'a': 1, 'b': 2, 'args': (), 'c': 3, 'd': 4, 'kwargs': {}}

Bu — dekoratorlar va validatsiyada juda foydali.


3. Tez ma'lumotnoma

Qoidalar

python
f(1, b=2)           ✅ pozitsion → nomli
f(a=1, 2)           ❌ SyntaxError
f(1, a=2)           ❌ multiple values
f(1, 2, d=4)        ❌ unexpected keyword
f(c=3, a=1, b=2)    ✅ nomli tartib erkin

Qachon nomli

Bool argument           DOIM nomli ⭐
2+ bir xil turda        boshi=0, oxiri=10
Sukut qiymatli          kodlash="utf-8"
Ma'no tushunarsiz       urinishlar=3
Kelajakda o'zgarishi    xavfsizroq

Pozitsion yetarli:  len(r), max(a,b), r.append(x)

API dizayni

python
✅ Yangi parametr OXIRIGA, sukut bilan
✅ Yoki * dan keyin
❌ O'rtaga qo'shish       — pozitsion chaqiruv buziladi
❌ Tartibni o'zgartirish  — jimgina noto'g'ri natija
❌ Nomni o'zgartirish     — nomli chaqiruv buziladi
   → def f(x, /)  bilan nomni yoping

** ochish

python
f(**{"a": 1})               ✅
f(**{1: "a"})               ❌ keywords must be strings
f(**{"a":1}, **{"a":2})     ❌ multiple values
f(**{**d1, **d2})           ✅ birlashtirish
g(**{"class": 1})           ✅ **kwargs bo'lsa — identifikator shart emas

inspect

python
sig = inspect.signature(f)
p.kind: POSITIONAL_ONLY | POSITIONAL_OR_KEYWORD | VAR_POSITIONAL
        | KEYWORD_ONLY | VAR_KEYWORD
sig.bind(...).arguments     argumentlarni bog'lash

4. Batafsil misollar

Misol 1 — Qoidalar va tuzoqlar

python
"""Nomli argumentlarning barcha qoidalari."""

print("=== 1. To'rt shakl ===")


def f(a, b, c=3):
    return a, b, c


SHAKLLAR = [
    ("f(1, 2)",             lambda: f(1, 2)),
    ("f(1, 2, 3)",          lambda: f(1, 2, 3)),
    ("f(1, b=2)",           lambda: f(1, b=2)),
    ("f(1, 2, c=30)",       lambda: f(1, 2, c=30)),
    ("f(a=1, b=2)",         lambda: f(a=1, b=2)),
    ("f(c=30, a=1, b=2)",   lambda: f(c=30, a=1, b=2)),
    ("f(b=2, a=1)",         lambda: f(b=2, a=1)),
]

for kod, fn in SHAKLLAR:
    print(f"  {kod:<24} → {fn()}")

print(f"\n  ⭐ Nomli argumentlarda TARTIB ERKIN")


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

XATOLAR = [
    ("f(1)",                "f(1)",                 TypeError),
    ("f(1, 2, 3, 4)",       "f(1, 2, 3, 4)",        TypeError),
    ("f(1, a=2)",           "f(1, a=2)",            TypeError),
    ("f(1, 2, d=4)",        "f(1, 2, d=4)",         TypeError),
    ("f(a=1, b=2, a=3)",    "f(a=1, b=2, a=3)",     SyntaxError),
]

for nom, kod, kutilgan in XATOLAR:
    try:
        eval(kod)
        natija = "✅ ishladi"
    except (TypeError, SyntaxError) as x:
        natija = f"❌ {type(x).__name__}: {x if not isinstance(x, SyntaxError) else x.msg}"
    print(f"  {nom:<22} {natija}")

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

print("""
  ⭐ Ikki xil xato:
     SyntaxError  — kod noto'g'ri yozilgan (kompilyatsiyada)
     TypeError    — argumentlar mos kelmadi (ish vaqtida)
""")


print("\n=== 3. Hisoblash tartibi ===")

kuzatuv = []


def kuzat(nom, qiymat):
    kuzatuv.append(nom)
    return qiymat


def g(a, b, c):
    return a, b, c


kuzatuv.clear()
natija = g(c=kuzat("c", 3), a=kuzat("a", 1), b=kuzat("b", 2))

print(f"  g(c=kuzat('c',3), a=kuzat('a',1), b=kuzat('b',2))\n")
print(f"    Natija:            {natija}")
print(f"    Hisoblash tartibi: {kuzatuv}")

print("""
  ⭐ Argumentlar YOZILISH tartibida hisoblanadi,
     lekin parametrlarga NOM bo'yicha bog'lanadi.
""")


print("\n=== 4. ⚠️ Bool argumentlar ===")


def qidir(matn, naqsh, katta_kichik=False, butun_soz=False,
          teskari=False, sanash=False):
    natija = []
    if katta_kichik:
        natija.append("katta-kichik farqlanadi")
    if butun_soz:
        natija.append("butun so'z")
    if teskari:
        natija.append("teskari")
    if sanash:
        natija.append("sanash")
    return f"qidir({naqsh!r}: {', '.join(natija) or 'sukut'})"


print(f"  ❌ Pozitsion:")
print(f"    qidir(matn, 'x', True, False, True, False)")
print(f"    → {qidir('matn', 'x', True, False, True, False)}")
print(f"    ⚠️ Qaysi True nimani anglatadi?\n")

print(f"  ✅ Nomli:")
print(f"    qidir(matn, 'x', katta_kichik=True, teskari=True)")
print(f"    → {qidir('matn', 'x', katta_kichik=True, teskari=True)}")

print("""
  ⭐ ENG MUHIM QOIDA:
     Bool argument nomsiz — deyarli har doim xato.
""")

print(f"  Standart kutubxonadan namunalar:")
NAMUNALAR = [
    "sorted(r, reverse=True)",
    "json.dumps(d, indent=2, sort_keys=True)",
    "open(yol, newline='')",
    "re.sub(naqsh, yangi, matn, count=1)",
    "subprocess.run(cmd, capture_output=True, check=True)",
]
for n in NAMUNALAR:
    print(f"    {n}")


print("\n=== 5. Bir xil turdagi argumentlar ===")


def kesim(matn, boshi, oxiri, qadam=1):
    return matn[boshi:oxiri:qadam]


def masofa(x1, y1, x2, y2):
    return ((x2 - x1) ** 2 + (y2 - y1) ** 2) ** 0.5


print(f"  ⚠️ kesim('abcdefgh', 2, 6, 2)")
print(f"     → {kesim('abcdefgh', 2, 6, 2)}")
print(f"     Qaysi son nima?\n")

print(f"  ✅ kesim('abcdefgh', boshi=2, oxiri=6, qadam=2)")
print(f"     → {kesim('abcdefgh', boshi=2, oxiri=6, qadam=2)}\n")

print(f"  ⚠️ masofa(0, 0, 3, 4) → {masofa(0, 0, 3, 4)}")
print(f"  ✅ masofa(x1=0, y1=0, x2=3, y2=4) → {masofa(x1=0, y1=0, x2=3, y2=4)}")

print(f"\n  ⚠️ Tartibni adashtirish oson:")
print(f"     masofa(0, 3, 0, 4) → {masofa(0, 3, 0, 4)}   ← boshqa natija!")
print(f"     Nomli bilan bunday xato bo'lmaydi")


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


def ulan(host, port, ssl=False, timeout=30):
    return f"{'https' if ssl else 'http'}://{host}:{port} (timeout={timeout})"


SINOVLAR = [
    ("f(**{'host':'x','port':1})",      {"host": "x", "port": 1}),
    ("f(**{'host':'x','port':1,'ssl':True})",
     {"host": "x", "port": 1, "ssl": True}),
    ("f(**{'host':'x'})",               {"host": "x"}),
    ("f(**{'host':'x','port':1,'yangi':1})",
     {"host": "x", "port": 1, "yangi": 1}),
    ("f(**{1:'x'})",                    {1: "x"}),
]

for nom, kwargs in SINOVLAR:
    try:
        natija = ulan(**kwargs)
    except TypeError as x:
        natija = f"❌ {x}"
    print(f"  {nom:<40}")
    print(f"    → {natija}")

print(f"\n  Aralash:")
print(f"    ulan('x', 5432, **{{'ssl': True}})")
print(f"    → {ulan('x', 5432, **{'ssl': True})}")

print(f"\n  ⚠️ Ikki lug'atda bir xil kalit:")
try:
    ulan(**{"host": "a"}, **{"host": "b", "port": 1})
except TypeError as x:
    print(f"    ulan(**d1, **d2) → ❌ {x}")
print(f"    ulan(**{{**d1, **d2}}) → "
      f"{ulan(**{**{'host': 'a'}, **{'host': 'b', 'port': 1}})}   ✅")


print("\n=== 7. **kwargs bilan erkin kalitlar ===")


def g(**kwargs):
    return kwargs


ERKIN = [
    ("{'oddiy': 1}",        {"oddiy": 1}),
    ("{'1-kalit': 1}",      {"1-kalit": 1}),
    ("{'bo`sh joy': 1}",    {"bo'sh joy": 1}),
    ("{'class': 1}",        {"class": 1}),
    ("{'': 1}",             {"": 1}),
    ("{1: 1}",              {1: 1}),
]

print(f"  def g(**kwargs): return kwargs\n")
for nom, d in ERKIN:
    try:
        natija = f"✅ {g(**d)}"
    except TypeError as x:
        natija = f"❌ {x}"
    print(f"  g(**{nom:<18}) → {natija}")

print("""
  ⭐ **kwargs — oddiy lug'at, kalitlari identifikator bo'lishi SHART EMAS.
     Lekin ular faqat ** orqali uzatiladi:

       g(class=1)          ❌ SyntaxError
       g(**{"class": 1})   ✅
""")

Natijaning muhim qismi:

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

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

=== 3. Hisoblash tartibi ===
    Natija:            (1, 2, 3)
    Hisoblash tartibi: ['c', 'a', 'b']

=== 7. **kwargs bilan erkin kalitlar ===
  g(**{'1-kalit': 1}      ) → ✅ {'1-kalit': 1}
  g(**{'class': 1}        ) → ✅ {'class': 1}
  g(**{1: 1}              ) → ❌ keywords must be strings

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

Misol 2 — API dizayni va evolyutsiya

python
"""Parametr tartibi va nomlari — ochiq shartnoma."""

import warnings

print("=== 1. ⚠️ Tartibni o'zgartirish ===")


def bol_v1(a, b):
    """Versiya 1."""
    return a / b


def bol_v2(b, a):
    """⚠️ Versiya 2 — tartib o'zgardi."""
    return a / b


print(f"  v1: def bol(a, b): return a / b")
print(f"  v2: def bol(b, a): return a / b   ⚠️ tartib almashdi\n")

print(f"  Pozitsion chaqiruv:")
print(f"    bol_v1(10, 2) = {bol_v1(10, 2)}")
print(f"    bol_v2(10, 2) = {bol_v2(10, 2)}   ⚠️ JIMGINA boshqa natija!")

print(f"\n  Nomli chaqiruv:")
print(f"    bol_v1(a=10, b=2) = {bol_v1(a=10, b=2)}")
print(f"    bol_v2(a=10, b=2) = {bol_v2(a=10, b=2)}   ✅ bir xil")

print("""
  ⭐ Nomli chaqiruv tartib o'zgarishidan HIMOYALAYDI.
     Pozitsion chaqiruv — jimgina buziladi (xato yo'q!).
""")


print("\n=== 2. ⚠️ O'rtaga parametr qo'shish ===")


def yarat_v1(nom, yosh):
    return f"{nom} ({yosh})"


def yarat_v2(nom, familiya, yosh):
    """⚠️ familiya O'RTAGA qo'shildi."""
    return f"{nom} {familiya} ({yosh})"


def yarat_v3(nom, yosh, familiya=""):
    """✅ familiya OXIRIGA, sukut bilan."""
    return f"{nom} {familiya} ({yosh})".replace("  ", " ")


print(f"  Eski kod: yarat('Aziz', 30)\n")
print(f"  v1: {yarat_v1('Aziz', 30)}")
try:
    print(f"  v2: {yarat_v2('Aziz', 30)}")
except TypeError as x:
    print(f"  v2: ❌ TypeError: {x}")
print(f"  v3: {yarat_v3('Aziz', 30)}   ✅ eski kod ishlaydi")

print(f"\n  ⚠️ Yanada yomoni — sukut bilan o'rtaga:")


def yarat_v4(nom, familiya="", yosh=0):
    return f"{nom} {familiya} ({yosh})"


print(f"    def yarat(nom, familiya='', yosh=0)")
print(f"    yarat('Aziz', 30) → {yarat_v4('Aziz', 30)}")
print(f"    ⚠️ 30 familiya ga tushdi — JIMGINA noto'g'ri!")


print("\n=== 3. ⚠️ Parametr nomini o'zgartirish ===")


def qayta_ishla_v1(royxat):
    return len(royxat)


def qayta_ishla_v2(elementlar):
    """⚠️ Nom o'zgardi."""
    return len(elementlar)


print(f"  v1: def qayta_ishla(royxat)")
print(f"  v2: def qayta_ishla(elementlar)\n")

print(f"  Pozitsion chaqiruv:")
print(f"    qayta_ishla_v1([1,2]) = {qayta_ishla_v1([1, 2])}")
print(f"    qayta_ishla_v2([1,2]) = {qayta_ishla_v2([1, 2])}   ✅")

print(f"\n  Nomli chaqiruv:")
print(f"    qayta_ishla_v1(royxat=[1,2]) = {qayta_ishla_v1(royxat=[1, 2])}")
try:
    qayta_ishla_v2(royxat=[1, 2])
except TypeError as x:
    print(f"    qayta_ishla_v2(royxat=[1,2]) → ❌ {x}")

print("""
  ⭐ Parametr NOMLARI ham ochiq API!
     Ularni o'zgartirish nomli chaqiruvlarni buzadi.
""")


print("\n=== 4. ✅ Himoya: faqat pozitsion (/) ===")


def qayta_ishla_himoyalangan(royxat, /):
    """/ — royxat nomi YOPIQ (6-dars)."""
    return len(royxat)


print(f"  def qayta_ishla(royxat, /):\n")
print(f"    qayta_ishla([1,2])         = {qayta_ishla_himoyalangan([1, 2])}   ✅")
try:
    qayta_ishla_himoyalangan(royxat=[1, 2])
except TypeError as x:
    print(f"    qayta_ishla(royxat=[1,2])  → ❌ {x}")

print("""
  ⭐ / bilan parametr nomi ICHKI tafsilotga aylanadi —
     uni erkin o'zgartirish mumkin.

     Standart kutubxonada ko'p ishlatiladi:
       len(obj, /), abs(x, /), pow(base, exp, mod=None)
""")


print("\n=== 5. Deprecation naqshi ===")


def qayta_ishla_v3(elementlar=None, *, royxat=None):
    """Eski `royxat` nomini vaqtincha qo'llab-quvvatlaydi."""
    if royxat is not None:
        if elementlar is not None:
            raise TypeError("elementlar va royxat birga berilmaydi")
        warnings.warn(
            "royxat parametri eskirgan, elementlar ishlating",
            DeprecationWarning,
            stacklevel=2,
        )
        elementlar = royxat
    if elementlar is None:
        raise TypeError("elementlar majburiy")
    return len(elementlar)


print(f"  def f(elementlar=None, *, royxat=None):\n")

with warnings.catch_warnings(record=True) as ogohlar:
    warnings.simplefilter("always")

    print(f"    f([1,2])              = {qayta_ishla_v3([1, 2])}   ✅ yangi")
    print(f"    f(elementlar=[1,2])   = {qayta_ishla_v3(elementlar=[1, 2])}   ✅")
    natija = qayta_ishla_v3(royxat=[1, 2])
    print(f"    f(royxat=[1,2])       = {natija}   ⚠️ ishlaydi + ogohlantirish")

    print(f"\n    Ogohlantirishlar:")
    for o in ogohlar:
        print(f"      {o.category.__name__}: {o.message}")

try:
    qayta_ishla_v3([1], royxat=[2])
except TypeError as x:
    print(f"\n    f([1], royxat=[2]) → ❌ {x}")


print("\n=== 6. ✅ Xavfsiz evolyutsiya ===")

print("""
  ┌───────────────────────────────┬──────────────────────────────┐
  │ O'zgarish                     │ Xavfsizmi                    │
  ├───────────────────────────────┼──────────────────────────────┤
  │ Yangi parametr OXIRIGA+sukut  │ ✅ Ha                        │
  │ Yangi parametr * dan keyin    │ ✅ Ha (eng xavfsiz)          │
  │ Sukut qiymatni o'zgartirish   │ ⚠️ Xatti-harakat o'zgaradi   │
  │ Parametrni o'rtaga qo'shish   │ ❌ Yo'q                      │
  │ Tartibni o'zgartirish         │ ❌ Yo'q (jimgina buziladi)   │
  │ Nomni o'zgartirish            │ ❌ Yo'q (nomli chaqiruvlar)  │
  │ Parametrni olib tashlash      │ ❌ Yo'q                      │
  │ Majburiyni ixtiyoriy qilish   │ ✅ Ha                        │
  │ Ixtiyoriyni majburiy qilish   │ ❌ Yo'q                      │
  │ / qo'shish (nomni yopish)     │ ❌ Yo'q (nomli chaqiruvlar)  │
  │ * qo'shish (nomni majburiy)   │ ❌ Yo'q (pozitsion chaqiruv) │
  └───────────────────────────────┴──────────────────────────────┘
""")

print(f"  ⭐ ENG XAVFSIZ dizayn — boshidan:\n")
print(f"""    def f(majburiy, /, *, ixtiyoriy1=None, ixtiyoriy2=None):
        #     ↑ nom yopiq      ↑ tartib muhim emas

    • majburiy nomini erkin o'zgartirish mumkin
    • yangi ixtiyoriy parametr har doim qo'shish mumkin
    • ixtiyoriylar tartibi muhim emas
""")


print("\n=== 7. Standart kutubxonadan namunalar ===")

NAMUNALAR = [
    ("sorted(iterable, /, *, key=None, reverse=False)",
     "iterable nomi yopiq, key/reverse faqat nomli"),
    ("open(file, mode='r', buffering=-1, encoding=None, ...)",
     "ko'p ixtiyoriy — amalda nomli ishlatiladi"),
    ("dict.get(key, default=None, /)",
     "ikkalasi ham faqat pozitsion"),
    ("print(*values, sep=' ', end='\\n', file=None, flush=False)",
     "*values dan keyin — hammasi faqat nomli"),
    ("json.dumps(obj, *, skipkeys=False, indent=None, ...)",
     "obj dan keyin — hammasi faqat nomli"),
]

for imzo, izoh in NAMUNALAR:
    print(f"  {imzo}")
    print(f"    → {izoh}\n")

import inspect
print(f"  Haqiqiy imzolar:")
for f in [sorted, print, len]:
    try:
        print(f"    {f.__name__:<10} {inspect.signature(f)}")
    except ValueError:
        print(f"    {f.__name__:<10} (C funksiyasi — imzo yo'q)")

Natijaning muhim qismi:

text
=== 1. ⚠️ Tartibni o'zgartirish ===
  Pozitsion chaqiruv:
    bol_v1(10, 2) = 5.0
    bol_v2(10, 2) = 0.2   ⚠️ JIMGINA boshqa natija!

  Nomli chaqiruv:
    bol_v1(a=10, b=2) = 5.0
    bol_v2(a=10, b=2) = 5.0   ✅ bir xil

=== 4. ✅ Himoya: faqat pozitsion (/) ===
    qayta_ishla([1,2])         = 2   ✅
    qayta_ishla(royxat=[1,2])  → ❌ qayta_ishla_himoyalangan() got some
    positional-only arguments passed as keyword arguments: 'royxat'

=== 5. Deprecation naqshi ===
    Ogohlantirishlar:
      DeprecationWarning: royxat parametri eskirgan, elementlar ishlating

Nima ko'rsatdi: 2.3-bo'lim.

Misol 3 — inspect va argumentlarni bog'lash

python
"""Funksiya imzosini tahlil qilish va argumentlarni bog'lash."""

import inspect
from functools import wraps

print("=== 1. Imzo tahlili ===")


def toliq(a, b, /, c, d=4, *args, e, f=6, **kwargs):
    """Barcha parametr turlari."""
    return locals()


sig = inspect.signature(toliq)

print(f"  def toliq(a, b, /, c, d=4, *args, e, f=6, **kwargs):\n")
print(f"  Imzo: {sig}\n")

print(f"  {'Parametr':<12} {'Kind':<24} {'Sukut'}")
print("  " + "─" * 50)
for nom, p in sig.parameters.items():
    sukut = "—" if p.default is p.empty else repr(p.default)
    print(f"  {nom:<12} {p.kind.name:<24} {sukut}")

print(f"\n  Guruhlar:")
GURUHLAR = {}
for nom, p in sig.parameters.items():
    GURUHLAR.setdefault(p.kind.name, []).append(nom)
for kind, nomlar in GURUHLAR.items():
    print(f"    {kind:<24} {nomlar}")


print("\n=== 2. Argumentlarni bog'lash ===")

CHAQIRUVLAR = [
    "toliq(1, 2, 3, e=5)",
    "toliq(1, 2, c=3, e=5)",
    "toliq(1, 2, 3, 4, 5, 6, e=7, f=8, x=9)",
    "toliq(1, 2, 3)",
    "toliq(1, c=3, e=5)",
]

for kod in CHAQIRUVLAR:
    print(f"  {kod}")
    try:
        # Argumentlarni ajratish
        ichki = kod[kod.index("(") + 1:-1]
        bound = eval(f"sig.bind({ichki})")
        bound.apply_defaults()
        print(f"    ✅ {dict(bound.arguments)}")
    except TypeError as x:
        print(f"    ❌ TypeError: {x}")
    print()


print("=== 3. Amaliy: argumentlarni jurnalga yozish ===")


def jurnalga_yoz(f):
    """Chaqiruv argumentlarini nomlari bilan chiqaradi."""
    sig = inspect.signature(f)

    @wraps(f)
    def ichki(*args, **kwargs):
        bound = sig.bind(*args, **kwargs)
        bound.apply_defaults()
        argumentlar = ", ".join(
            f"{k}={v!r}" for k, v in bound.arguments.items()
        )
        print(f"    → {f.__name__}({argumentlar})")
        natija = f(*args, **kwargs)
        print(f"    ← {natija!r}")
        return natija

    return ichki


@jurnalga_yoz
def hisobla(asos, daraja=2, *, modul=None):
    natija = asos ** daraja
    return natija % modul if modul else natija


print(f"  @jurnalga_yoz\n  def hisobla(asos, daraja=2, *, modul=None):\n")

for kod, args, kwargs in [
    ("hisobla(5)", (5,), {}),
    ("hisobla(5, 3)", (5, 3), {}),
    ("hisobla(5, daraja=3, modul=7)", (5,), {"daraja": 3, "modul": 7}),
]:
    print(f"  {kod}:")
    hisobla(*args, **kwargs)
    print()


print("=== 4. Xavfsiz chaqirish ===")


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

    if any(p.kind is p.VAR_KEYWORD for p in parametrlar.values()):
        return f(**kwargs)          # **kwargs bor

    mos = {k: v for k, v in kwargs.items() if k in parametrlar}
    ortiqcha = set(kwargs) - set(mos)
    if ortiqcha:
        print(f"      (e'tiborsiz: {sorted(ortiqcha)})")
    return f(**mos)


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


def ulan_erkin(host, port, **qolgan):
    return f"{host}:{port} qolgan={qolgan}"


SOZLAMALAR = {"host": "db.uz", "port": 5432, "ssl": True,
              "noma'lum": 1, "yana_bir": 2}

print(f"  SOZLAMALAR = {SOZLAMALAR}\n")

print(f"  ulan(**SOZLAMALAR) to'g'ridan-to'g'ri:")
try:
    ulan(**SOZLAMALAR)
except TypeError as x:
    print(f"    ❌ {x}\n")

print(f"  xavfsiz_chaqir(ulan, **SOZLAMALAR):")
print(f"    → {xavfsiz_chaqir(ulan, **SOZLAMALAR)}\n")

print(f"  xavfsiz_chaqir(ulan_erkin, **SOZLAMALAR):")
print(f"    → {xavfsiz_chaqir(ulan_erkin, **SOZLAMALAR)}")


print("\n=== 5. Imzo validatori ===")


def imzoni_baholash(f) -> dict:
    """Funksiya imzosining sifat ko'rsatkichlari."""
    try:
        sig = inspect.signature(f)
    except (ValueError, TypeError):
        return {"xato": "imzo o'qib bo'lmadi"}

    ps = list(sig.parameters.values())

    pozitsion = [p for p in ps
                 if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD)]
    nomli = [p for p in ps if p.kind is p.KEYWORD_ONLY]
    bool_sukutli = [p for p in ps
                    if isinstance(p.default, bool)
                    and p.kind is p.POSITIONAL_OR_KEYWORD]
    ozgaruvchan_sukut = [p for p in ps
                         if isinstance(p.default, (list, dict, set))]

    ogohlar = []
    if len(pozitsion) > 4:
        ogohlar.append(f"{len(pozitsion)} pozitsion parametr (4 dan ko'p)")
    if bool_sukutli:
        ogohlar.append(
            f"bool parametr pozitsion bo'lishi mumkin: "
            f"{[p.name for p in bool_sukutli]}"
        )
    if ozgaruvchan_sukut:
        ogohlar.append(
            f"o'zgaruvchan sukut: {[p.name for p in ozgaruvchan_sukut]}"
        )
    if len(ps) > 8:
        ogohlar.append(f"{len(ps)} parametr — juda ko'p")

    return {
        "jami": len(ps),
        "pozitsion": len(pozitsion),
        "faqat_nomli": len(nomli),
        "ogohlar": ogohlar,
    }


def yomon1(a, b, c, d, e, f): ...
def yomon2(matn, tozala=True, qatiy=False, teskari=True): ...
def yomon3(a, r=[], d={}): ...
def yaxshi1(a, b, *, c=1, d=2): ...
def yaxshi2(malumot, /, *, sozlamalar=None): ...


FUNKSIYALAR = [yomon1, yomon2, yomon3, yaxshi1, yaxshi2, sorted, print]

for f in FUNKSIYALAR:
    nom = getattr(f, "__name__", str(f))
    natija = imzoni_baholash(f)
    if "xato" in natija:
        print(f"  {nom:<10} (imzo o'qib bo'lmadi)")
        continue
    belgi = "⚠️" if natija["ogohlar"] else "✅"
    print(f"  {belgi} {nom:<10} jami={natija['jami']}, "
          f"pozitsion={natija['pozitsion']}, nomli={natija['faqat_nomli']}")
    for o in natija["ogohlar"]:
        print(f"       • {o}")


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

import timeit


def f3(a, b, c):
    return a + b + c


SOZLASH = "from __main__ import f3\nd = {'a': 1, 'b': 2, 'c': 3}"

SINOVLAR = [
    ("f(1, 2, 3)",                  "f3(1, 2, 3)"),
    ("f(1, 2, c=3)",                "f3(1, 2, c=3)"),
    ("f(a=1, b=2, c=3)",            "f3(a=1, b=2, c=3)"),
    ("f(**d)",                      "f3(**d)"),
    ("f(**{'a':1,'b':2,'c':3})",    "f3(**{'a': 1, 'b': 2, 'c': 3})"),
]

natijalar = []
for nom, kod in SINOVLAR:
    vaqt = timeit.timeit(kod, setup=SOZLASH, number=3_000_000)
    natijalar.append((nom, vaqt))

eng_tez = min(v for _, v in natijalar)
print(f"  3M chaqiruv:\n")
print(f"  {'Chaqiruv':<28} {'Vaqt':>9} {'Nisbat':>9}")
print("  " + "─" * 50)
for nom, vaqt in natijalar:
    print(f"  {nom:<28} {vaqt:>7.3f} s {vaqt / eng_tez:>8.2f}x")

print("""
  ⚠️ Nomli argument ~20-40% sekinroq (nom bo'yicha qidiruv).

  ⭐ Lekin bu — nanosekundlar. Funksiya tanasi har doim ko'proq oladi.
     O'qilishni tanlang, tezlikni profillashdan keyin optimallashtiring.
""")

Natijaning muhim qismi:

text
=== 1. Imzo tahlili ===
  Parametr     Kind                     Sukut
  ──────────────────────────────────────────────────
  a            POSITIONAL_ONLY          —
  b            POSITIONAL_ONLY          —
  c            POSITIONAL_OR_KEYWORD    —
  d            POSITIONAL_OR_KEYWORD    4
  args         VAR_POSITIONAL           —
  e            KEYWORD_ONLY             —
  f            KEYWORD_ONLY             6
  kwargs       VAR_KEYWORD              —

=== 3. Amaliy: argumentlarni jurnalga yozish ===
  hisobla(5, daraja=3, modul=7):
    → hisobla(asos=5, daraja=3, modul=7)
    ← 6

=== 5. Imzo validatori ===
  ⚠️ yomon1     jami=6, pozitsion=6, nomli=0
       • 6 pozitsion parametr (4 dan ko'p)
  ⚠️ yomon2     jami=4, pozitsion=4, nomli=0
       • bool parametr pozitsion bo'lishi mumkin: ['tozala', 'qatiy', 'teskari']
  ✅ yaxshi1    jami=4, pozitsion=2, nomli=2

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

Misol 4 — Amaliy: konfiguratsiyalanadigan API

python
"""Nomli argumentlar bilan yaxshi API dizayni."""

import inspect
from dataclasses import dataclass
from enum import Enum

print("=== Jadval chizuvchi API ===\n")


class Tekislash(Enum):
    CHAP = "<"
    MARKAZ = "^"
    ONG = ">"


class Uslub(Enum):
    ODDIY = ("│", "─", "┌", "┐", "└", "┘", "├", "┤", "┬", "┴", "┼")
    QALIN = ("┃", "━", "┏", "┓", "┗", "┛", "┣", "┫", "┳", "┻", "╋")
    IKKI = ("║", "═", "╔", "╗", "╚", "╝", "╠", "╣", "╦", "╩", "╬")
    YOQ = (" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ")


def jadval(
    qatorlar: list[dict],
    /,                                  # ⭐ qatorlar nomi yopiq
    *,                                  # ⭐ qolgan hammasi FAQAT nomli
    ustunlar: tuple[str, ...] | None = None,
    sarlavha: str | None = None,
    uslub: Uslub = Uslub.ODDIY,
    tekislash: Tekislash | dict[str, Tekislash] = Tekislash.CHAP,
    raqamlar: bool = False,
    jami_qatori: bool = False,
    jami_ustunlari: tuple[str, ...] = (),
    maksimal_kenglik: int = 30,
    bosh_qiymat: str = "—",
) -> str:
    """Lug'atlar ro'yxatidan matn jadvali yaratadi.

    Barcha sozlamalar FAQAT nomli — chaqiruv o'z-o'zini hujjatlaydi.
    """
    if not qatorlar:
        return "(bo'sh)"

    ustunlar = ustunlar or tuple(qatorlar[0])
    v, h, yc, yo_, pc, po, chap, ong, yuq, past, orta = uslub.value

    def matn(q, u):
        qiymat = q.get(u)
        if qiymat is None:
            return bosh_qiymat
        if isinstance(qiymat, (int, float)) and not isinstance(qiymat, bool):
            return f"{qiymat:,}"
        return str(qiymat)[:maksimal_kenglik]

    barcha_qatorlar = list(qatorlar)
    if jami_qatori and jami_ustunlari:
        jami = {u: "JAMI" for u in ustunlar[:1]}
        for u in jami_ustunlari:
            jami[u] = sum(q.get(u, 0) for q in qatorlar
                          if isinstance(q.get(u), (int, float)))
        barcha_qatorlar.append(jami)

    kengliklar = {
        u: max(len(str(u)), max(len(matn(q, u)) for q in barcha_qatorlar))
        for u in ustunlar
    }
    if raqamlar:
        raqam_kengligi = max(3, len(str(len(qatorlar))))

    def tekislash_ol(u):
        if isinstance(tekislash, dict):
            return tekislash.get(u, Tekislash.CHAP).value
        return tekislash.value

    def chiziq(chap_b, orta_b, ong_b):
        qismlar = [h * (kengliklar[u] + 2) for u in ustunlar]
        if raqamlar:
            qismlar.insert(0, h * (raqam_kengligi + 2))
        return chap_b + orta_b.join(qismlar) + ong_b

    def qator_chiz(qiymatlar, tekislashlar):
        qismlar = [f" {q:{t}{kengliklar[u]}} "
                   for q, t, u in zip(qiymatlar, tekislashlar, ustunlar)]
        if raqamlar:
            qismlar.insert(0, f" {qiymatlar_raqami:>{raqam_kengligi}} ")
        return v + v.join(qismlar) + v

    natija = []

    if sarlavha:
        kenglik = sum(kengliklar.values()) + 3 * len(ustunlar) - 1
        if raqamlar:
            kenglik += raqam_kengligi + 3
        natija.append(f"{yc}{h * kenglik}{yo_}")
        natija.append(f"{v} {sarlavha:^{kenglik - 2}} {v}")
        natija.append(chiziq(chap, yuq, ong))
    else:
        natija.append(chiziq(yc, yuq, yo_))

    qiymatlar_raqami = "#"
    natija.append(qator_chiz(list(ustunlar), ["^"] * len(ustunlar)))
    natija.append(chiziq(chap, orta, ong))

    for i, q in enumerate(qatorlar, 1):
        qiymatlar_raqami = i
        natija.append(qator_chiz(
            [matn(q, u) for u in ustunlar],
            [tekislash_ol(u) for u in ustunlar],
        ))

    if jami_qatori and jami_ustunlari:
        natija.append(chiziq(chap, orta, ong))
        qiymatlar_raqami = ""
        jami_q = barcha_qatorlar[-1]
        natija.append(qator_chiz(
            [matn(jami_q, u) for u in ustunlar],
            [tekislash_ol(u) for u in ustunlar],
        ))

    natija.append(chiziq(pc, past, po))
    return "\n".join("  " + q for q in natija)


# ═══ NAMOYISH ═══

XODIMLAR = [
    {"ism": "Aziz", "bolim": "IT", "yosh": 30, "maosh": 7_000_000},
    {"ism": "Bobur", "bolim": "HR", "yosh": 25, "maosh": 5_000_000},
    {"ism": "Aziza", "bolim": "IT", "yosh": 35, "maosh": 8_500_000},
    {"ism": "Dilnoza", "bolim": "Moliya", "yosh": 28, "maosh": None},
]

print("=== 1. Sukut sozlamalar ===\n")
print(jadval(XODIMLAR))


print("\n\n=== 2. Sarlavha va raqamlar ===\n")
print(jadval(
    XODIMLAR,
    sarlavha="XODIMLAR RO'YXATI",
    raqamlar=True,
))


print("\n\n=== 3. Tekislash va uslub ===\n")
print(jadval(
    XODIMLAR,
    ustunlar=("ism", "yosh", "maosh"),
    uslub=Uslub.IKKI,
    tekislash={
        "ism": Tekislash.CHAP,
        "yosh": Tekislash.MARKAZ,
        "maosh": Tekislash.ONG,
    },
))


print("\n\n=== 4. Jami qatori ===\n")
print(jadval(
    XODIMLAR,
    sarlavha="MAOSH HISOBOTI",
    ustunlar=("ism", "bolim", "maosh"),
    uslub=Uslub.QALIN,
    tekislash={"maosh": Tekislash.ONG},
    jami_qatori=True,
    jami_ustunlari=("maosh",),
    bosh_qiymat="(yo'q)",
))


print("\n\n=== 5. ⭐ Chaqiruv o'z-o'zini hujjatlaydi ===\n")

print("""  ❌ Agar hammasi pozitsion bo'lganda:

     jadval(XODIMLAR, ("ism","bolim","maosh"), "MAOSH HISOBOTI",
            Uslub.QALIN, {...}, False, True, ("maosh",), 30, "(yo'q)")

     ← False va True nima? 30 nima?

  ✅ Nomli argumentlar bilan:

     jadval(
         XODIMLAR,
         sarlavha="MAOSH HISOBOTI",
         ustunlar=("ism", "bolim", "maosh"),
         uslub=Uslub.QALIN,
         jami_qatori=True,
         jami_ustunlari=("maosh",),
         bosh_qiymat="(yo'q)",
     )

     ← har argument o'zini tushuntiradi
""")


print("=== 6. Imzo tahlili ===\n")

sig = inspect.signature(jadval)

print(f"  {'Parametr':<20} {'Kind':<22} {'Sukut'}")
print("  " + "─" * 62)
for nom, p in sig.parameters.items():
    sukut = "—" if p.default is p.empty else repr(p.default)
    if len(sukut) > 18:
        sukut = sukut[:16] + "…"
    print(f"  {nom:<20} {p.kind.name:<22} {sukut}")

pozitsion = sum(1 for p in sig.parameters.values()
                if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD))
nomli = sum(1 for p in sig.parameters.values() if p.kind is p.KEYWORD_ONLY)

print(f"\n  Pozitsion: {pozitsion}, faqat nomli: {nomli}")
print("""
  ⭐ Dizayn qarorlari:

     qatorlar, /       — nom yopiq, kelajakda o'zgartirish mumkin
     *                 — qolgan HAMMASI faqat nomli
     bool parametrlar  — hech qachon pozitsion bo'lolmaydi
     Enum sozlamalar   — True/False o'rniga ma'noli qiymatlar
     Yangi parametr    — istalgan vaqtda qo'shish xavfsiz
""")


print("\n=== 7. Kelajakdagi kengaytirish ===\n")

print("""  Yangi parametr qo'shish — hech narsani buzmaydi:

     def jadval(qatorlar, /, *, ..., rang=None, eksport=None):
                                     ↑ yangi   ↑ yangi

     • Barcha mavjud chaqiruvlar ishlaydi
     • Tartib muhim emas
     • Sukut qiymat orqaga moslikni saqlaydi

  Solishtiring — pozitsion bo'lganda:

     def jadval(qatorlar, ustunlar, sarlavha, uslub, ..., rang, eksport)
                                                          ↑ oxiriga majburiy
     • Faqat oxiriga qo'shish mumkin
     • 12-argument sifatida chaqirish — o'qib bo'lmaydi
""")

Natijaning muhim qismi:

text
=== 2. Sarlavha va raqamlar ===

  ┌───────────────────────────────────────────┐
  │              XODIMLAR RO'YXATI                 │
  ├─────┬─────────┬────────┬──────┬───────────┤
  │   # │   ism   │ bolim  │ yosh │     maosh      │
  ├─────┼─────────┼────────┼──────┼───────────┤
  │   1 │ Aziz    │ IT     │ 30   │ 7,000,000      │
  │   2 │ Bobur   │ HR     │ 25   │ 5,000,000      │
  │   3 │ Aziza   │ IT     │ 35   │ 8,500,000      │
  │   4 │ Dilnoza │ Moliya │ 28   │ —              │
  └─────┴─────────┴────────┴──────┴───────────┘

=== 6. Imzo tahlili ===
  Parametr             Kind                   Sukut
  ──────────────────────────────────────────────────────────────
  qatorlar             POSITIONAL_ONLY        —
  ustunlar             KEYWORD_ONLY           None
  sarlavha             KEYWORD_ONLY           None
  uslub                KEYWORD_ONLY           <Uslub.ODDIY: ('…
  raqamlar             KEYWORD_ONLY           False

  Pozitsion: 1, faqat nomli: 9

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


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

Noto'g'ri fikr To'g'risi
"Nomli argument tartibi muhim" Tartib erkin (lekin hisoblash — yozilish tartibida)
"f(a=1, 2) ishlaydi" SyntaxError
"Parametr nomi ichki tafsilot" Ochiq API — o'zgartirish buzuvchi
"Parametr qo'shish har doim xavfsiz" Faqat oxiriga sukut bilan yoki * dan keyin
"** kalitlari identifikator bo'lishi kerak" **kwargs bo'lsa — shart emas
"f(**d1, **d2) birlashtiradi" Umumiy kalit bo'lsa TypeError
"Nomli argument sezilarli sekin" ~20-40% — nanosekundlar
"Bool argument pozitsion bo'lsa bo'ladi" Deyarli har doim o'qilishni buzadi
"/ va * — ekzotik" Standart kutubxonada keng ishlatiladi

6. Keng tarqalgan xatolar va yechimlari

1. Bool argument pozitsion

python
sarala(r, True)                     # ❌ True nima?
sarala(r, reverse=True)             # ✅

2. Nomli pozitsiondan oldin

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

3. Ikki lug'atni ** bilan

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

4. Parametr nomini o'zgartirish

python
def f(royxat): ...  →  def f(elementlar): ...     # ⚠️ buzuvchi
def f(royxat, /): ...                             # ✅ nom yopiq

5. Parametrni o'rtaga qo'shish

python
def f(a, yangi, b): ...             # ❌ barcha chaqiruv buziladi
def f(a, b, *, yangi=None): ...     # ✅

6. Mos kelmaydigan kalitlarni uzatish

python
f(**sozlamalar)                     # ❌ ortiqcha kalit bo'lsa
xavfsiz_chaqir(f, **sozlamalar)     # ✅ filtrlaydi

7. Sukut qiymatni o'zgartirish

python
def f(a, rejim="r"): ...  →  def f(a, rejim="w"): ...    # ⚠️ jimgina o'zgarish

8. Ko'p pozitsion parametr

python
def f(a, b, c, d, e, g): ...        # ❌
def f(a, /, *, b, c, d=1): ...      # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 7.2-dars (o'tilgan): argument uzatish asoslari
  • 7.3-dars (o'tilgan): sukut qiymatlar
  • 7.5-dars: *args va **kwargs
  • 7.6-dars: / va * — faqat pozitsion va faqat nomli
  • 8-qism: dataclass, metodlar imzosi
  • 10-qism: dekoratorlar, functools.wraps
  • inspect: imzo tahlili, bind, validatsiya
  • API dizayni: semantik versiyalash, deprecation

8. Eng yaxshi amaliyotlar

  1. Bool argumentni doim nom bilan. f(x, faol=True).

  2. Ikkitadan ko'p bir xil turdagi argument — nom bilan. kesim(m, boshi=0, oxiri=10).

  3. Muhim parametrlarni * bilan nomli qiling. Yangi parametr qo'shish xavfsiz bo'ladi.

  4. Ichki nomlarni / bilan yoping. Keyinchalik o'zgartirish mumkin bo'ladi.

  5. Parametr tartibi va nomlari — ochiq API. O'zgartirish — buzuvchi o'zgarish.

  6. Yangi parametr faqat oxiriga sukut bilan yoki * dan keyin.

  7. Eskirgan nom uchun DeprecationWarning. Bir necha versiya qo'llab-quvvatlang.

  8. Bool o'rniga Enum. Tekislash.MARKAZ True, False dan aniqroq.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
def f(a, b, c=3): return a, b, c
def g(**kw): return kw

1.  print(f(1, 2))
2.  print(f(c=3, a=1, b=2))
3.  print(f(1, b=2))
4.  f(a=1, 2)
5.  f(1, a=2)
6.  f(1, 2, d=4)
7.  print(f(**{"a": 1, "b": 2}))
8.  print(f(1, **{"b": 2, "c": 30}))
9.  f(**{"a": 1}, **{"a": 2})
10. print(g(**{"class": 1, "1-x": 2}))
11. g(**{1: "a"})
12. print(f(*[1, 2], **{"c": 3}))
Javoblar
  1. (1, 2, 3)
  2. (1, 2, 3) — tartib erkin
  3. (1, 2, 3)
  4. SyntaxError — nomli pozitsiondan oldin
  5. TypeError — a ikki marta
  6. TypeError — d yo'q
  7. (1, 2, 3)
  8. (1, 2, 30)
  9. TypeError — a ikki marta
  10. {'class': 1, '1-x': 2} — **kwargs erkin
  11. TypeError: keywords must be strings
  12. (1, 2, 3)

Vazifa 2: Xatolarni tuzating

python
1.  sarala(r, True, False)
2.  f(a=1, 2)
3.  ulan(**standart, **foydalanuvchi)   # umumiy kalitlar bor
4.  def f(a, yangi, b): ...             # v2 da o'rtaga qo'shildi
5.  def f(elementlar): ...              # v1 da royxat edi
6.  kesim(matn, 2, 6, 2)
7.  f(**barcha_sozlamalar)              # ortiqcha kalitlar
8.  def yarat(nom, aktiv, korinadigan, tahrirlanadigan): ...
Javoblar
python
1.  sarala(r, reverse=True, barqaror=False)
2.  f(1, b=2)   yoki   f(a=1, b=2)
3.  ulan(**{**standart, **foydalanuvchi})
4.  def f(a, b, *, yangi=None): ...
5.  def f(elementlar=None, *, royxat=None): ...  + DeprecationWarning
6.  kesim(matn, boshi=2, oxiri=6, qadam=2)
7.  xavfsiz_chaqir(f, **barcha_sozlamalar)
8.  def yarat(nom, *, aktiv=True, korinadigan=True, tahrirlanadigan=True): ...

Vazifa 3: API refaktoring

Berilgan funksiyani qayta loyihalang:

python
def yubor(kimga, mavzu, matn, html, muhim, nusxa, yashirin_nusxa,
          ilova, kodlash, urinishlar, kutish):
  1. / va * bilan
  2. Bool argumentlarni nomli qiling
  3. Bog'liq parametrlarni guruhlang (dataclass)
  4. Yangi parametr qo'shishni sinab ko'ring
  5. inspect bilan imzoni tahlil qiling
  6. Eski API uchun moslashtiruvchi (adapter) yozing

Vazifa 4: Xavfsiz chaqiruvchi

xavfsiz_chaqir ni kengaytiring:

  1. Pozitsion argumentlarni ham qo'llab-quvvatlasin
  2. *args bo'lsa to'g'ri ishlasin
  3. Majburiy argument yetishmasa aniq xato bersin
  4. Tur ko'rsatkichlariga qarab tekshirsin
  5. Statistika: qaysi kalitlar ishlatildi/tashlandi
  6. Dekorator versiyasi: @moslashuvchan

Vazifa 5: Deprecation vositasi

Dekorator yozing:

python
@eskirgan_parametr(eski="royxat", yangi="elementlar", versiya="2.0")
def f(elementlar): ...
  1. Eski nomni yangi nomga yo'naltirsin
  2. DeprecationWarning bersin
  3. Ikkalasi berilsa xato bersin
  4. Bir necha eskirgan nomni qo'llab-quvvatlasin
  5. Docstring ga avtomatik eslatma qo'shsin
  6. Test yozing (pytest.warns)

Vazifa 6: Imzo linteri

Vosita yozing:

  1. Modul funksiyalarini skanerlaydi
  2. Har biri uchun ogohlantirishlar:
    • 4+ pozitsion parametr
    • Bool parametr pozitsion bo'lishi mumkin
    • O'zgaruvchan sukut
    • * yoki / yo'q
    • 8+ parametr
  3. Tuzatish taklifini beradi
  4. Hisobot chiqaradi (jadval)
  5. ruff natijasi bilan solishtiradi

Vazifa 7: O'ylash

Nega Python nomli argumentlarda tartibni erkin qildi, lekin pozitsion argument nomlidan keyin kelishini taqiqladi?

Javob

Chunki aks holda bog'lash noaniq bo'lardi.

Muammo:

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

f(a=1, 2, 3)                # taqiqlangan

Agar bunga ruxsat berilsa, 2 va 3 qaysi parametrga tegishli?

Ikki mumkin bo'lgan qoida:

Qoida A: "qolgan pozitsiyalar tartib bo'yicha"

python
f(a=1, 2, 3)                # b=2, c=3?

Lekin:

python
f(b=2, 1, 3)                # a=1, c=3?
                            # yoki a=1, keyin 3 qaerga?

Qoida B: "pozitsiyalar o'z o'rnida"

python
f(a=1, 2, 3)                # 2 → 1-pozitsiya = a?  ❌ konflikt

Har ikki qoida ham chalkash va xatoga moyil.

Pythonning yechimi — sodda va aniq:

1. Pozitsion argumentlar CHAPDAN o'ngga parametrlarga bog'lanadi
2. Keyin nomli argumentlar nom bo'yicha bog'lanadi
3. Konflikt bo'lsa — xato

Bu — bir yo'nalishli algoritm. Uni tushuntirish va amalga oshirish oson.

Nega nomlilar orasida tartib erkin:

Nomli argumentlar nom bo'yicha bog'lanadi — pozitsiya ahamiyatsiz:

python
f(c=3, a=1, b=2)            # har biri o'z nomiga

Hech qanday noaniqlik yo'q. Cheklash ham foyda bermasdi.

Amaliy foyda:

python
# Muhim argumentlarni oldinga qo'yish
yubor(
    kimga="aziz@mail.uz",
    mavzu="Muhim",
    ...20 qator sozlama...
)

# Yoki mantiqiy guruhlash
chiz(
    x=10, y=20,             # koordinata
    kenglik=100, balandlik=50,      # o'lcham
    rang="qizil",           # ko'rinish
)

O'quvchi uchun qulay tartibni tanlash mumkin.

Lekin hisoblash tartibi — yozilish tartibida:

python
f(c=birinchi(), a=ikkinchi())

birinchi() avval chaqiriladi. Bu — muhim, chunki argumentlar yon ta'sirli bo'lishi mumkin:

python
f(b=stack.pop(), a=stack.pop())     # tartib muhim!

Boshqa tillar:

Til Nomli argument Aralash tartib
Python Pozitsion oldin
C# Pozitsion oldin (7.2 gacha)
Swift Majburiy Ta'rif tartibida!
Kotlin Pozitsion oldin
Ruby (hash orqali) Pozitsion oldin
JavaScript (obyekt orqali) —
Go —
C, Java —

Swift qiziq: u nomli argumentlarni majburiy qiladi va tartib ta'rif tartibida bo'lishi kerak:

swift
func f(a: Int, b: Int) {}
f(a: 1, b: 2)               // ✅
f(b: 2, a: 1)               // ❌ xato!

Swift falsafasi: "chaqiruv ta'rifga o'xshasin". Python falsafasi: "chaqiruvchiga erkinlik".

C# 7.2 dan keyin:

csharp
f(a: 1, 2, 3)               // ✅ ruxsat — "non-trailing named arguments"

C# qoida A ni tanladi: nomli argument o'z pozitsiyasida bo'lsa, keyingi pozitsionlar davom etadi. Bu — moslashuvchan, lekin qoida murakkabroq.

Xulosa: Python soddalikni tanladi. "Pozitsion oldin" qoidasi — bir jumlada tushuntiriladi va hech qanday chekka holat yaratmaydi. Bu — Zen ning "Sodda murakkabdan yaxshi" tamoyiliga mos.

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


Xulosa

Bu darsda nomli argumentlarni chuqur o'rgandik.

Eng muhim uch fikr:

  1. Bool argumentni doim nom bilan uzating. f(x, True, False) — o'qib bo'lmaydi, f(x, faol=True, modal=False) — o'z-o'zini hujjatlaydi. Bu — nomli argumentlarning eng muhim qo'llanishi.

  2. Parametr tartibi VA nomlari — ochiq API. Tartibni o'zgartirish pozitsion chaqiruvlarni jimgina buzadi (xato yo'q, natija noto'g'ri). Nomni o'zgartirish nomli chaqiruvlarni buzadi. / bilan nomni yoping, * bilan nomlini majburiy qiling.

  3. Qoida: pozitsion argumentlar nomlidan oldin. Nomlilar orasida tartib erkin, lekin hisoblash yozilish tartibida bo'ladi. f(a=1, 2) — SyntaxError, f(1, a=2) — TypeError.

Keyingi darsda *args va **kwargs ni ko'ramiz: cheksiz argumentlar, ularni yo'naltirish va dekoratorlar uchun asos.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
7.4-dars: Nomli argumentlar — IlmHamroh