IlmHamroh
Python kursi/Funksiyalar6/14-dars35 daqiqa
Mundarija (21)

7.6-dars: Faqat pozitsion va faqat nomli argumentlar

7-QISM — FUNKSIYALAR · 6-dars


1. Kirish va motivatsiya

Standart kutubxona hujjatida g'alati belgilar uchraydi:

python
sorted(iterable, /, *, key=None, reverse=False)
len(obj, /)
dict.get(key, default=None, /)
print(*values, sep=' ', end='\n', file=None, flush=False)

/ va * — bu nima?

Ular argumentlarni qanday uzatish mumkinligini boshqaradi:

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

f(1, 2, c=3)                # ✅
f(1, b=2, c=3)              # ✅
f(a=1, b=2, c=3)            # ❌ a — faqat pozitsion
f(1, 2, 3)                  # ❌ c — faqat nomli

Nega bu kerak?

python
# Muammo 1: parametr nomini o'zgartirish API ni buzadi
def qayta_ishla(royxat): ...
qayta_ishla(royxat=[1, 2])          # foydalanuvchi shunday yozdi

def qayta_ishla(elementlar): ...    # nom o'zgartirildi
qayta_ishla(royxat=[1, 2])          # ❌ buzildi

# Muammo 2: bool argument pozitsion
sarala(r, True)                     # ⚠️ True nima?

Bu darsda:

  • / — faqat pozitsion parametrlar
  • * — faqat nomli parametrlar
  • Nega kerak — API dizayni
  • To'liq imzo shakli va barcha kombinatsiyalar
  • **kwargs bilan o'zaro ta'sir
  • Standart kutubxonada qo'llanishi

2. Nazariya — chuqur tushuntirish

2.1. * — faqat nomli argumentlar

* dan keyingi barcha parametrlar faqat nom bilan uzatiladi:

python
def f(a, b, *, c, d=4):
    return a, b, c, d

f(1, 2, c=3)                # ✅ (1, 2, 3, 4)
f(1, 2, c=3, d=40)          # ✅
f(1, 2, 3)                  # ❌ TypeError: takes 2 positional arguments but 3 were given

Ikki shakl:

python
def f(a, *, b): ...         # * — qolgan pozitsion QABUL QILINMAYDI
def f(a, *args, b): ...     # *args — qolgan pozitsion yig'iladi

Ikkalasida ham b — faqat nomli.

* dan keyin kamida bitta parametr:

python
def f(a, *): ...            # ❌ SyntaxError: named arguments must follow bare *
def f(a, *, b): ...         # ✅

Sukut qiymatsiz ham bo'lishi mumkin:

python
def f(*, a):                # a — majburiy va faqat nomli
    ...
f()                         # ❌ TypeError: missing 1 required keyword-only argument: 'a'
f(a=1)                      # ✅

Bu — 7.3-darsdagi "sukutlar oxirida" qoidasidan istisno:

python
def f(a=1, b): ...          # ❌ SyntaxError
def f(*, a=1, b): ...       # ✅ ruxsat!

Chunki * dan keyin tartib ahamiyatsiz — hammasi nom bilan uzatiladi.

2.2. / — faqat pozitsion argumentlar

Python 3.8+ (PEP 570). / dan oldingi parametrlar faqat pozitsiya bilan uzatiladi:

python
def f(a, b, /, c):
    return a, b, c

f(1, 2, 3)                  # ✅
f(1, 2, c=3)                # ✅
f(1, b=2, c=3)              # ❌ TypeError: got some positional-only arguments passed as keyword arguments: 'b'
f(a=1, b=2, c=3)            # ❌

Parametr nomi ICHKI tafsilotga aylanadi:

python
def f(royxat, /): ...
# royxat nomini erkin o'zgartirish mumkin — hech kim unga tayanolmaydi

/ bitta bo'lishi kerak va * dan oldin:

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

Tarixi: / dan oldin ham C da yozilgan funksiyalar shunday ishlardi:

python
len(obj=[1, 2])             # ❌ TypeError — Python 3.8 dan oldin ham

Lekin Pythonda yozish mumkin emas edi. PEP 570 buni tuzatdi.

2.3. To'liq shakl

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

Beshta guruh, qat'iy tartibda:

# Guruh Sintaksis inspect kind
1 Faqat pozitsion / dan oldin POSITIONAL_ONLY
2 Pozitsion yoki nomli Oddiy POSITIONAL_OR_KEYWORD
3 Qolgan pozitsion *args VAR_POSITIONAL
4 Faqat nomli * dan keyin KEYWORD_ONLY
5 Qolgan nomli **kwargs VAR_KEYWORD

Barcha kombinatsiyalar:

python
def f(a): ...                       # 2
def f(a, /): ...                    # 1
def f(*, a): ...                    # 4
def f(a, /, b): ...                 # 1, 2
def f(a, *, b): ...                 # 2, 4
def f(a, /, *, b): ...              # 1, 4  ⭐ eng qat'iy
def f(a, /, b, *, c): ...           # 1, 2, 4
def f(*args): ...                   # 3
def f(**kwargs): ...                # 5
def f(*args, **kwargs): ...         # 3, 5
def f(a, /, b, *args, c, **kw): ... # hammasi

2.4. Nega kerak — API dizayni

1. / — parametr nomini yashirish:

python
# Nomsiz
def qayta_ishla(royxat):
    return len(royxat)

qayta_ishla(royxat=[1, 2])          # foydalanuvchi shunday yozdi

# Nom o'zgardi — API buzildi
def qayta_ishla(elementlar): ...
qayta_ishla(royxat=[1, 2])          # ❌
python
# / bilan
def qayta_ishla(royxat, /):
    return len(royxat)

qayta_ishla(royxat=[1, 2])          # ❌ darhol — nom API emas
qayta_ishla([1, 2])                 # ✅ yagona yo'l

# Endi nomni erkin o'zgartirish mumkin
def qayta_ishla(elementlar, /): ...  # ✅ hech narsa buzilmaydi

2. * — o'qilishni majburlash:

python
# * siz
def sarala(r, teskari=False, barqaror=True): ...
sarala(data, True, False)           # ⚠️ nima nima?

# * bilan
def sarala(r, *, teskari=False, barqaror=True): ...
sarala(data, True, False)           # ❌ darhol
sarala(data, teskari=True)          # ✅ yagona yo'l

3. * — kelajakda parametr qo'shish xavfsiz:

python
def f(a, *, b=1, c=2): ...
# Yangi parametr qo'shish — hech narsa buzilmaydi
def f(a, *, b=1, c=2, d=3): ...     # ✅
# Tartib ham muhim emas
def f(a, *, d=3, b=1, c=2): ...     # ✅

4. / — **kwargs bilan nom to'qnashuvi:

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

f("x", nom="y")                     # ❌ multiple values for argument 'nom'

/ bilan:

python
def f(nom, /, **kwargs):
    return nom, kwargs

f("x", nom="y")                     # ✅ ('x', {'nom': 'y'})

Bu — dict va boshqa konteynerlar uchun muhim:

python
d = dict(self="x")                  # ✅ ishlaydi, chunki dict.__init__ da / bor

5. / — pozitsion tezroq:

python
f(1, 2, 3)                  # ~60 ns
f(a=1, b=2, c=3)            # ~85 ns

Tor sikllarda (masalan key= funksiyasi) bu sezilishi mumkin.

2.5. **kwargs bilan o'zaro ta'sir

Muammo — nom to'qnashuvi:

python
def sozla(nom, **sozlamalar):
    return nom, sozlamalar

sozla("test", nom="x")              # ❌ TypeError
sozla("test", debug=True)           # ✅

Foydalanuvchi nom kalitini uzata olmaydi.

Yechim — /:

python
def sozla(nom, /, **sozlamalar):
    return nom, sozlamalar

sozla("test", nom="x")              # ✅ ('test', {'nom': 'x'})

Standart kutubxonada:

python
dict(self=1, dict=2)                # ✅ — dict.__init__(self, /, **kwargs)
namedtuple("N", ["a"])._replace(self=1)     # maxsus ishlov

Metodlarda self:

python
class A:
    def metod(self, nom): ...

a.metod(self=1)                     # ❌ multiple values for argument 'self'

class A:
    def metod(self, /, **kwargs): ...

a.metod(self=1)                     # ✅

CPython ichki turlarida self doim / dan oldin.

2.6. Standart kutubxonada

python
import inspect

inspect.signature(sorted)
# (iterable, /, *, key=None, reverse=False)

Naqshlar:

python
# 1. Asosiy argument — pozitsion, sozlamalar — nomli
sorted(iterable, /, *, key=None, reverse=False)
sum(iterable, /, start=0)
min(arg1, arg2, *args, key=None)

# 2. Hammasi pozitsion (oddiy funksiyalar)
len(obj, /)
abs(x, /)
pow(base, exp, mod=None)
isinstance(obj, class_or_tuple, /)

# 3. *args dan keyin — hammasi nomli
print(*values, sep=' ', end='\n', file=None, flush=False)
max(*args, key=None, default=...)

# 4. Ko'p ixtiyoriy sozlama
open(file, mode='r', buffering=-1, encoding=None, errors=None,
     newline=None, closefd=True, opener=None)
json.dumps(obj, *, skipkeys=False, ensure_ascii=True, indent=None, ...)

Ba'zi funksiyalarda / yo'q (eskirgan):

python
open(file="x.txt")                  # ✅ ishlaydi — `file` nomi API

Yangi kodda / qo'shish orqaga moslikni buzardi.

inspect bilan tekshirish:

python
for f in [len, sorted, print, open]:
    try:
        print(f.__name__, inspect.signature(f))
    except ValueError:
        print(f.__name__, "(imzo yo'q)")

2.7. Amaliy tavsiyalar

Yangi funksiya uchun sukut naqsh:

python
def f(asosiy, /, *, sozlama1=None, sozlama2=None):
    #    ↑ nom yopiq  ↑ hammasi nomli

Bu:

  • Asosiy parametr nomini keyinchalik o'zgartirish mumkin
  • Yangi sozlama qo'shish xavfsiz
  • Chaqiruv o'z-o'zini hujjatlaydi

Qachon / ishlatish:

Holat / kerakmi
Nomi ma'nosiz (obj, x, self) Ha
**kwargs bilan to'qnashuv xavfi Ha
Matematik funksiya (abs, pow) Ha
Nomi ma'noli va foydali Yo'q
Foydalanuvchi nom bilan yozishi mumkin Yo'q

Qachon * ishlatish:

Holat * kerakmi
Bool parametr Doim
3+ ixtiyoriy sozlama Ha
Kelajakda kengaytiriladi Ha
Ma'nosi kontekstsiz noaniq Ha
1-2 aniq argument Yo'q

Orqaga moslik:

python
# Mavjud funksiyaga / yoki * qo'shish — BUZUVCHI
def f(a, b): ...                    # v1
def f(a, /, b): ...                 # v2 — f(a=1, b=2) buziladi
def f(a, *, b): ...                 # v2 — f(1, 2) buziladi

Shuning uchun boshidan to'g'ri loyihalang.


3. Tez ma'lumotnoma

Ikki belgi

python
def f(a, /, b, *, c):
      ↑        ↑
      /        * dan
      dan      keyin —
      oldin —  FAQAT
      FAQAT    NOMLI
      POZITSION

f(1, 2, c=3)        ✅
f(1, b=2, c=3)      ✅
f(a=1, ...)         ❌ a faqat pozitsion
f(1, 2, 3)          ❌ c faqat nomli

To'liq shakl

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

1 POSITIONAL_ONLY        / dan oldin
2 POSITIONAL_OR_KEYWORD  oddiy
3 VAR_POSITIONAL         *args
4 KEYWORD_ONLY           * dan keyin
5 VAR_KEYWORD            **kwargs

Nega kerak

/  → parametr NOMI ichki tafsilot (keyinchalik o'zgartirish mumkin)
/  → **kwargs bilan nom to'qnashuvi yo'q
/  → pozitsion chaqiruv tezroq

*  → bool argument o'qiladigan bo'ladi
*  → yangi parametr qo'shish xavfsiz
*  → tartib muhim emas
*  → sukutsiz parametr sukutlidan keyin bo'lishi mumkin

Sintaksis qoidalari

python
def f(a, *): ...            ❌ * dan keyin kamida bitta
def f(a, /, b, /): ...      ❌ bitta /
def f(a, *, b, /): ...      ❌ / — * dan OLDIN
def f(*, a=1, b): ...       ✅ * dan keyin tartib erkin

Tavsiya etilgan naqsh

python
def f(asosiy, /, *, sozlama1=None, sozlama2=None):

Mavjud funksiyaga qo'shish — BUZUVCHI o'zgarish


4. Batafsil misollar

Misol 1 — Ikki belgi

python
"""/ va * — to'liq namoyish."""

import inspect

print("=== 1. * — faqat nomli ===")


def f_yulduz(a, b, *, c, d=4):
    return a, b, c, d


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

CHAQIRUVLAR = [
    "f_yulduz(1, 2, c=3)",
    "f_yulduz(1, 2, c=3, d=40)",
    "f_yulduz(1, b=2, c=3)",
    "f_yulduz(a=1, b=2, c=3)",
    "f_yulduz(1, 2, 3)",
    "f_yulduz(1, 2, 3, 4)",
    "f_yulduz(1, 2)",
]

for kod in CHAQIRUVLAR:
    try:
        natija = f"✅ {eval(kod)}"
    except TypeError as x:
        natija = f"❌ {x}"
    print(f"  {kod:<32} {natija}")


print("\n=== 2. / — faqat pozitsion ===")


def f_slesh(a, b, /, c):
    return a, b, c


print(f"  def f(a, b, /, c):\n")

CHAQIRUVLAR = [
    "f_slesh(1, 2, 3)",
    "f_slesh(1, 2, c=3)",
    "f_slesh(1, b=2, c=3)",
    "f_slesh(a=1, b=2, c=3)",
]

for kod in CHAQIRUVLAR:
    try:
        natija = f"✅ {eval(kod)}"
    except TypeError as x:
        natija = f"❌ {x}"
    print(f"  {kod:<32} {natija}")


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


def f_ikkala(a, /, b, *, c):
    return a, b, c


print(f"  def f(a, /, b, *, c):")
print(f"        ↑     ↑     ↑")
print(f"        │     │     └─ faqat nomli")
print(f"        │     └─────── ikkalasi ham")
print(f"        └───────────── faqat pozitsion\n")

CHAQIRUVLAR = [
    "f_ikkala(1, 2, c=3)",
    "f_ikkala(1, b=2, c=3)",
    "f_ikkala(a=1, b=2, c=3)",
    "f_ikkala(1, 2, 3)",
]

for kod in CHAQIRUVLAR:
    try:
        natija = f"✅ {eval(kod)}"
    except TypeError as x:
        natija = f"❌ {str(x)[:52]}"
    print(f"  {kod:<28} {natija}")


print("\n=== 4. Barcha kombinatsiyalar ===")

SHAKLLAR = [
    ("def f(a)",                    "def _f1(a): pass"),
    ("def f(a, /)",                 "def _f2(a, /): pass"),
    ("def f(*, a)",                 "def _f3(*, a): pass"),
    ("def f(a, /, b)",              "def _f4(a, /, b): pass"),
    ("def f(a, *, b)",              "def _f5(a, *, b): pass"),
    ("def f(a, /, *, b)",           "def _f6(a, /, *, b): pass"),
    ("def f(a, /, b, *, c)",        "def _f7(a, /, b, *, c): pass"),
    ("def f(*args)",                "def _f8(*args): pass"),
    ("def f(**kwargs)",             "def _f9(**kwargs): pass"),
    ("def f(a, /, b, *args, c, **kw)",
     "def _f10(a, /, b, *args, c, **kw): pass"),
]

print(f"  {'Shakl':<32} {'Imzo'}")
print("  " + "─" * 68)
for nom, kod in SHAKLLAR:
    exec(kod)
    fn = eval(kod.split("(")[0].replace("def ", ""))
    print(f"  {nom:<32} {inspect.signature(fn)}")


print("\n=== 5. Sintaksis xatolari ===")

XATOLAR = [
    "def f(a, *): pass",
    "def f(a, /, b, /): pass",
    "def f(a, *, b, /): pass",
    "def f(/, a): pass",
    "def f(*, /): pass",
    "def f(a, *args, /): pass",
]

for kod in XATOLAR:
    try:
        exec(kod)
        print(f"  ✅ {kod}")
    except SyntaxError as x:
        print(f"  ❌ {kod:<34} {x.msg}")


print("\n=== 6. ⭐ * dan keyin tartib erkin ===")

print(f"  Oddiy parametrlarda sukutlar OXIRIDA:")
try:
    exec("def f(a=1, b): pass")
except SyntaxError as x:
    print(f"    def f(a=1, b): pass  →  ❌ {x.msg}")

print(f"\n  * dan keyin — tartib ERKIN:")


def f_erkin(*, a=1, b, c=3, d):
    return a, b, c, d


print(f"    def f(*, a=1, b, c=3, d): pass  →  ✅")
print(f"    Imzo: {inspect.signature(f_erkin)}")
print(f"    f(b=2, d=4) = {f_erkin(b=2, d=4)}")

print("""
  ⭐ Sabab: * dan keyin hammasi NOM bilan uzatiladi,
     shuning uchun tartib ahamiyatsiz.
""")


print("\n=== 7. inspect bilan tahlil ===")


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


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

GURUHLAR = {}
for nom, p in sig.parameters.items():
    GURUHLAR.setdefault(p.kind, []).append(nom)

IZOHLAR = {
    inspect.Parameter.POSITIONAL_ONLY: "/ dan oldin",
    inspect.Parameter.POSITIONAL_OR_KEYWORD: "oddiy",
    inspect.Parameter.VAR_POSITIONAL: "*args",
    inspect.Parameter.KEYWORD_ONLY: "* dan keyin",
    inspect.Parameter.VAR_KEYWORD: "**kwargs",
}

print(f"  {'Kind':<24} {'Parametrlar':<16} {'Sintaksis'}")
print("  " + "─" * 56)
for kind in inspect.Parameter.__dict__.values():
    if not isinstance(kind, inspect._ParameterKind):
        continue
    nomlar = GURUHLAR.get(kind, [])
    if nomlar:
        print(f"  {kind.name:<24} {str(nomlar):<16} {IZOHLAR[kind]}")


print("\n=== 8. Standart kutubxonada ===")

FUNKSIYALAR = [len, abs, sorted, print, sum, max, min, round, isinstance,
               open, repr, hash]

print(f"  {'Funksiya':<14} {'Imzo'}")
print("  " + "─" * 70)
for f in FUNKSIYALAR:
    try:
        print(f"  {f.__name__:<14} {inspect.signature(f)}")
    except (ValueError, TypeError):
        print(f"  {f.__name__:<14} (imzo o'qib bo'lmadi)")

print(f"\n  Metodlar:")
for tur, metodlar in [(str, ["find", "replace", "split"]),
                      (dict, ["get", "pop", "setdefault"]),
                      (list, ["append", "insert", "index"])]:
    for m in metodlar:
        f = getattr(tur, m)
        try:
            print(f"    {tur.__name__}.{m:<12} {inspect.signature(f)}")
        except (ValueError, TypeError):
            print(f"    {tur.__name__}.{m:<12} (imzo yo'q)")

Natijaning muhim qismi:

text
=== 2. / — faqat pozitsion ===
  def f(a, b, /, c):

  f_slesh(1, 2, 3)                 ✅ (1, 2, 3)
  f_slesh(1, 2, c=3)               ✅ (1, 2, 3)
  f_slesh(1, b=2, c=3)             ❌ f_slesh() got some positional-only
                                      arguments passed as keyword arguments: 'b'

=== 5. Sintaksis xatolari ===
  ❌ def f(a, *): pass                named arguments must follow bare *
  ❌ def f(a, /, b, /): pass          / may appear only once
  ❌ def f(a, *, b, /): pass          / must be ahead of *
  ❌ def f(/, a): pass                at least one argument must precede /

=== 8. Standart kutubxonada ===
  Funksiya       Imzo
  ──────────────────────────────────────────────────────────────────────
  len            (obj, /)
  abs            (x, /)
  sorted         (iterable, /, *, key=None, reverse=False)
  sum            (iterable, /, start=0)
  round          (number, ndigits=None)
  isinstance     (obj, class_or_tuple, /)

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

Misol 2 — Nega kerak

python
"""/ va * ning amaliy foydasi."""

import inspect
import warnings

print("=== 1. / — parametr nomini yashirish ===")


def qayta_ishla_v1(royxat):
    """v1 — nom ochiq."""
    return len(royxat)


def qayta_ishla_v2(elementlar):
    """v2 — nom o'zgartirildi."""
    return len(elementlar)


def himoyalangan_v1(royxat, /):
    """v1 — nom YOPIQ."""
    return len(royxat)


def himoyalangan_v2(elementlar, /):
    """v2 — nom o'zgartirildi."""
    return len(elementlar)


print(f"  Foydalanuvchi kodi: f(royxat=[1, 2])\n")

print(f"  {'Funksiya':<24} {'Natija'}")
print("  " + "─" * 56)
for nom, f in [("qayta_ishla_v1", qayta_ishla_v1),
               ("qayta_ishla_v2", qayta_ishla_v2),
               ("himoyalangan_v1", himoyalangan_v1),
               ("himoyalangan_v2", himoyalangan_v2)]:
    try:
        natija = f"✅ {f(royxat=[1, 2])}"
    except TypeError as x:
        natija = f"❌ {str(x)[:40]}"
    print(f"  {nom:<24} {natija}")

print(f"\n  Pozitsion chaqiruv: f([1, 2])\n")
for nom, f in [("qayta_ishla_v2", qayta_ishla_v2),
               ("himoyalangan_v2", himoyalangan_v2)]:
    print(f"  {nom:<24} ✅ {f([1, 2])}")

print("""
  ⭐ / bilan:
     • Foydalanuvchi nomni ishlata OLMAYDI (darhol xato)
     • Shuning uchun nomni keyinchalik o'zgartirish XAVFSIZ
     • Parametr nomi — ichki tafsilot
""")


print("\n=== 2. * — bool argumentlarni majburiy nomlash ===")


def sarala_v1(r, teskari=False, barqaror=True, tozala=False):
    """* siz — pozitsion mumkin."""
    return f"sarala(teskari={teskari}, barqaror={barqaror}, tozala={tozala})"


def sarala_v2(r, *, teskari=False, barqaror=True, tozala=False):
    """* bilan — faqat nomli."""
    return f"sarala(teskari={teskari}, barqaror={barqaror}, tozala={tozala})"


print(f"  ⚠️ * siz:")
print(f"    sarala_v1(r, True, False, True)")
print(f"    → {sarala_v1([], True, False, True)}")
print(f"    ⚠️ Chaqiruvni o'qib nima nimaligini bilib bo'lmaydi\n")

print(f"  ✅ * bilan:")
try:
    sarala_v2([], True, False, True)
except TypeError as x:
    print(f"    sarala_v2(r, True, False, True) → ❌ {str(x)[:56]}")
print(f"    sarala_v2(r, teskari=True, tozala=True)")
print(f"    → {sarala_v2([], teskari=True, tozala=True)}")


print("\n=== 3. * — kelajakda kengaytirish ===")


def hisobla_v1(malumot, *, aniqlik=2, birlik="so'm"):
    return f"hisobla(aniqlik={aniqlik}, birlik={birlik})"


def hisobla_v2(malumot, *, birlik="so'm", aniqlik=2, yaxlitlash="yuqoriga"):
    """Yangi parametr qo'shildi VA tartib o'zgardi."""
    return (f"hisobla(aniqlik={aniqlik}, birlik={birlik}, "
            f"yaxlitlash={yaxlitlash})")


print(f"  v1: def f(malumot, *, aniqlik=2, birlik=\"so'm\")")
print(f"  v2: def f(malumot, *, birlik=\"so'm\", aniqlik=2, yaxlitlash=...)")
print(f"      ↑ yangi parametr + tartib o'zgardi\n")

ESKI_CHAQIRUVLAR = [
    ("f(d)",                        {}),
    ("f(d, aniqlik=3)",             {"aniqlik": 3}),
    ("f(d, birlik='USD')",          {"birlik": "USD"}),
    ("f(d, aniqlik=0, birlik='€')", {"aniqlik": 0, "birlik": "€"}),
]

print(f"  {'Eski chaqiruv':<30} {'v1':<14} {'v2'}")
print("  " + "─" * 62)
for kod, kwargs in ESKI_CHAQIRUVLAR:
    a = "✅" if hisobla_v1([], **kwargs) else "❌"
    b = "✅" if hisobla_v2([], **kwargs) else "❌"
    print(f"  {kod:<30} {a:<14} {b}")

print(f"""
  ⭐ Barcha eski chaqiruvlar ishlaydi — chunki
     * dan keyin TARTIB ahamiyatsiz.
""")


print("\n=== 4. / — **kwargs bilan to'qnashuv ===")


def sozla_yomon(nom, **sozlamalar):
    return nom, sozlamalar


def sozla_yaxshi(nom, /, **sozlamalar):
    return nom, sozlamalar


print(f"  def f(nom, **sozlamalar)      — / siz")
print(f"  def f(nom, /, **sozlamalar)   — / bilan\n")

SINOVLAR = [
    ("f('x', debug=True)",      ("x",), {"debug": True}),
    ("f('x', nom='y')",         ("x",), {"nom": "y"}),
]

print(f"  {'Chaqiruv':<24} {'/ siz':<28} {'/ bilan'}")
print("  " + "─" * 66)
for kod, args, kwargs in SINOVLAR:
    try:
        a = str(sozla_yomon(*args, **kwargs))
    except TypeError as x:
        a = f"❌ {str(x)[:24]}"
    try:
        b = str(sozla_yaxshi(*args, **kwargs))
    except TypeError as x:
        b = f"❌ {str(x)[:24]}"
    print(f"  {kod:<24} {a:<28} {b}")

print(f"\n  Standart kutubxonada:")
print(f"    dict(self=1, dict=2) = {dict(self=1, dict=2)}")
print(f"    ⭐ dict.__init__(self, /, **kwargs) — shuning uchun ishlaydi")

print(f"\n  Metodlarda ham:")


class A:
    def yomon(self, nom):
        return nom

    def yaxshi(self, /, **kwargs):
        return kwargs


a = A()
try:
    a.yomon(self=1, nom="x")
except TypeError as x:
    print(f"    a.yomon(self=1, nom='x') → ❌ {str(x)[:44]}")
print(f"    a.yaxshi(self=1, nom='x') → ✅ {a.yaxshi(self=1, nom='x')}")


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

import timeit


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


def f3_slesh(a, b, c, /):
    return a + b + c


SOZLASH = "from __main__ import f3, f3_slesh"

SINOVLAR = [
    ("f(1, 2, 3)",              "f3(1, 2, 3)"),
    ("f(a=1, b=2, c=3)",        "f3(a=1, b=2, c=3)"),
    ("f_slesh(1, 2, 3)",        "f3_slesh(1, 2, 3)"),
]

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

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

print("""
  ⭐ Pozitsion chaqiruv tezroq (nom qidiruvi yo'q).
     Farq kichik, lekin tor sikllarda (key=, filter=) sezilishi mumkin.
""")


print("\n=== 6. ⚠️ Orqaga moslik ===")

print("""
  Mavjud funksiyaga / yoki * qo'shish — BUZUVCHI o'zgarish:

    v1: def f(a, b): ...
        f(1, 2)        ✅
        f(a=1, b=2)    ✅

    v2: def f(a, /, b): ...
        f(1, 2)        ✅
        f(a=1, b=2)    ❌ BUZILDI

    v3: def f(a, *, b): ...
        f(1, 2)        ❌ BUZILDI
        f(a=1, b=2)    ✅

  ⭐ Shuning uchun BOSHIDAN to'g'ri loyihalang.
""")

print(f"  Bosqichma-bosqich o'tish (deprecation):\n")


def f_otish(a, b=None, /, *, yangi_b=None):
    """Eski pozitsion `b` ni vaqtincha qo'llab-quvvatlaydi."""
    if b is not None:
        warnings.warn(
            "Ikkinchi pozitsion argument eskirgan, yangi_b= ishlating",
            DeprecationWarning, stacklevel=2,
        )
        yangi_b = b
    return a, yangi_b


with warnings.catch_warnings(record=True) as ogohlar:
    warnings.simplefilter("always")
    print(f"    f_otish(1, 2)          → {f_otish(1, 2)}")
    print(f"    f_otish(1, yangi_b=2)  → {f_otish(1, yangi_b=2)}")
    for o in ogohlar:
        print(f"    ⚠️ {o.category.__name__}: {o.message}")

Natijaning muhim qismi:

text
=== 1. / — parametr nomini yashirish ===
  Foydalanuvchi kodi: f(royxat=[1, 2])

  Funksiya                 Natija
  ────────────────────────────────────────────────────────
  qayta_ishla_v1           ✅ 2
  qayta_ishla_v2           ❌ qayta_ishla_v2() got an unexpected
  himoyalangan_v1          ❌ himoyalangan_v1() got some positional
  himoyalangan_v1          ❌ himoyalangan_v1() got some positional-on

=== 4. / — **kwargs bilan to'qnashuv ===
  Chaqiruv                 / siz                        / bilan
  ──────────────────────────────────────────────────────────────────
  f('x', debug=True)       ('x', {'debug': True})       ('x', {'debug': True})
  f('x', nom='y')          ❌ sozla_yomon() got multip   ('x', {'nom': 'y'})

    dict(self=1, dict=2) = {'self': 1, 'dict': 2}

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

Misol 3 — Dizayn qarorlari

python
"""Qachon / va * ishlatish."""

import inspect
from dataclasses import dataclass
from enum import Enum

print("=== 1. Naqsh: asosiy + sozlamalar ===")


def formatla(matn, /, *, kenglik=80, tekislash="chap",
             toldirish=" ", kesish=True):
    """⭐ Tavsiya etilgan naqsh."""
    BELGILAR = {"chap": "<", "markaz": "^", "ong": ">"}
    if kesish and len(matn) > kenglik:
        matn = matn[:kenglik - 1] + "…"
    return f"{matn:{toldirish}{BELGILAR[tekislash]}{kenglik}}"


print(f"  def formatla(matn, /, *, kenglik=80, tekislash='chap', ...):\n")

NAMUNALAR = [
    ("formatla('Salom', kenglik=20)", {"kenglik": 20}),
    ("formatla('Salom', kenglik=20, tekislash='markaz')",
     {"kenglik": 20, "tekislash": "markaz"}),
    ("formatla('Salom', kenglik=20, tekislash='ong', toldirish='.')",
     {"kenglik": 20, "tekislash": "ong", "toldirish": "."}),
]

for kod, kwargs in NAMUNALAR:
    print(f"  {kod}")
    print(f"    → [{formatla('Salom', **kwargs)}]")

print(f"\n  Xatolar:")
for kod, args, kwargs in [
    ("formatla(matn='x')", (), {"matn": "x"}),
    ("formatla('x', 20)", ("x", 20), {}),
]:
    try:
        formatla(*args, **kwargs)
        natija = "✅"
    except TypeError as x:
        natija = f"❌ {str(x)[:48]}"
    print(f"    {kod:<24} {natija}")


print("\n=== 2. Qachon / kerak ===")

QARORLAR = [
    ("obj, x, self, iterable",  "✅ Ha",   "nomi ma'nosiz"),
    ("**kwargs bilan",          "✅ Ha",   "nom to'qnashuvi xavfi"),
    ("abs(x), len(obj)",        "✅ Ha",   "matematik/oddiy"),
    ("fayl_yoli, foydalanuvchi_id", "❌ Yo'q", "nomi ma'noli"),
    ("kenglik, balandlik",      "❌ Yo'q", "nom bilan o'qiladi"),
    ("konfiguratsiya",          "❌ Yo'q", "nom foydali"),
]

print(f"  {'Parametr':<28} {'/ kerakmi':<10} Sabab")
print("  " + "─" * 62)
for parametr, qaror, sabab in QARORLAR:
    print(f"  {parametr:<28} {qaror:<10} {sabab}")


print("\n=== 3. Qachon * kerak ===")

QARORLAR = [
    ("bool parametr",           "✅ DOIM", "True/False o'qib bo'lmaydi"),
    ("3+ ixtiyoriy sozlama",    "✅ Ha",   "tartibni eslash qiyin"),
    ("kelajakda kengayadi",     "✅ Ha",   "yangi parametr xavfsiz"),
    ("noaniq ma'no (3, 5)",     "✅ Ha",   "nom kerak"),
    ("f(a, b) — 2 ta aniq",     "❌ Yo'q", "ortiqcha shovqin"),
    ("qosh(x, y)",              "❌ Yo'q", "ma'no ravshan"),
]

print(f"  {'Holat':<28} {'* kerakmi':<10} Sabab")
print("  " + "─" * 62)
for holat, qaror, sabab in QARORLAR:
    print(f"  {holat:<28} {qaror:<10} {sabab}")


print("\n=== 4. Bir funksiyani uch xil loyihalash ===")


def yubor_v1(kimga, mavzu, matn, html, muhim, nusxa, ilova):
    """❌ Hammasi pozitsion."""
    return "yuborildi"


def yubor_v2(kimga, mavzu, matn, *, html=False, muhim=False,
             nusxa=(), ilova=()):
    """⚠️ Yaxshiroq — sozlamalar nomli."""
    return "yuborildi"


def yubor_v3(kimga, mavzu, matn, /, *, html=False, muhim=False,
             nusxa=(), ilova=()):
    """✅ Eng yaxshi — asosiy nomlar ham yopiq."""
    return "yuborildi"


print(f"  v1: def yubor(kimga, mavzu, matn, html, muhim, nusxa, ilova)")
print(f"  v2: def yubor(kimga, mavzu, matn, *, html=False, ...)")
print(f"  v3: def yubor(kimga, mavzu, matn, /, *, html=False, ...)\n")

CHAQIRUVLAR = [
    ('yubor("a@x", "Mavzu", "Matn", True, False, (), ())',
     ("a@x", "Mavzu", "Matn", True, False, (), ()), {}),
    ('yubor("a@x", "Mavzu", "Matn", html=True)',
     ("a@x", "Mavzu", "Matn"), {"html": True}),
    ('yubor(kimga="a@x", mavzu="M", matn="T")',
     (), {"kimga": "a@x", "mavzu": "M", "matn": "T"}),
]

print(f"  {'Chaqiruv':<50} {'v1':<5} {'v2':<5} {'v3'}")
print("  " + "─" * 70)
for kod, args, kwargs in CHAQIRUVLAR:
    natijalar = []
    for f in [yubor_v1, yubor_v2, yubor_v3]:
        try:
            f(*args, **kwargs)
            natijalar.append("✅")
        except TypeError:
            natijalar.append("❌")
    print(f"  {kod[:48]:<50} {natijalar[0]:<5} {natijalar[1]:<5} {natijalar[2]}")

print("""
  ⭐ v3 yagona to'g'ri chaqiruv shaklini majburlaydi:
     yubor("a@x", "Mavzu", "Matn", html=True, muhim=False)

     • Asosiy uchtasi — tartib bilan (tabiiy o'qiladi)
     • Sozlamalar — nom bilan (o'z-o'zini hujjatlaydi)
     • Nomlarni keyinchalik o'zgartirish mumkin
""")


print("\n=== 5. Sinf metodlarida ===")


class Hujjat:
    def __init__(self, matn, /, *, kodlash="utf-8", til="uz"):
        self.matn = matn
        self.kodlash = kodlash
        self.til = til

    def saqla(self, yol, /, *, formatlash=True, zaxira=False):
        return f"saqla({yol}, formatlash={formatlash}, zaxira={zaxira})"

    def almashtir(self, eski, yangi, /, *, hammasi=True, registr=False):
        return f"almashtir({eski!r}→{yangi!r}, hammasi={hammasi})"

    @staticmethod
    def yukla(yol, /, **sozlamalar):
        """/ bilan — 'yol' kaliti sozlamalar ichida bo'lishi mumkin."""
        return f"yukla({yol}, {sozlamalar})"


h = Hujjat("Salom dunyo", til="en")

print(f"  h = Hujjat('Salom dunyo', til='en')\n")
print(f"  {h.saqla('fayl.txt', zaxira=True)}")
print(f"  {h.almashtir('a', 'b', registr=True)}")
print(f"  {Hujjat.yukla('x.txt', yol='boshqa', kodlash='cp1251')}")

print(f"\n  ⭐ yukla da / bo'lgani uchun 'yol' kaliti sozlamalarga tushdi")

print(f"\n  Imzolar:")
for nom in ["__init__", "saqla", "almashtir", "yukla"]:
    f = getattr(Hujjat, nom)
    print(f"    {nom:<12} {inspect.signature(f)}")


print("\n=== 6. Imzo sifatini baholash ===")


def imzoni_baholash(f) -> tuple[int, list[str]]:
    """Imzo dizayni sifatini baholaydi (0-100)."""
    try:
        sig = inspect.signature(f)
    except (ValueError, TypeError):
        return 0, ["imzo o'qib bo'lmadi"]

    ps = list(sig.parameters.values())
    if not ps:
        return 100, []

    ball = 100
    ogohlar = []

    pozitsion = [p for p in ps if p.kind is p.POSITIONAL_OR_KEYWORD]
    faqat_poz = [p for p in ps if p.kind is p.POSITIONAL_ONLY]
    faqat_nomli = [p for p in ps if p.kind is p.KEYWORD_ONLY]

    # Bool parametr pozitsion bo'lishi mumkin
    bool_poz = [p.name for p in pozitsion if isinstance(p.default, bool)]
    if bool_poz:
        ball -= 30
        ogohlar.append(f"bool pozitsion bo'lishi mumkin: {bool_poz}")

    # Ko'p pozitsion
    jami_poz = len(pozitsion) + len(faqat_poz)
    if jami_poz > 4:
        ball -= 20
        ogohlar.append(f"{jami_poz} pozitsion parametr (4 dan ko'p)")

    # Ko'p sukut qiymatli pozitsion
    sukutli_poz = [p.name for p in pozitsion if p.default is not p.empty]
    if len(sukutli_poz) > 2:
        ball -= 15
        ogohlar.append(f"{len(sukutli_poz)} sukutli pozitsion — * qo'shing")

    # * yo'q va sozlamalar bor
    if not faqat_nomli and len(sukutli_poz) >= 2:
        ball -= 15
        ogohlar.append("* yo'q — sozlamalar pozitsion uzatilishi mumkin")

    # O'zgaruvchan sukut
    ozgaruvchan = [p.name for p in ps
                   if isinstance(p.default, (list, dict, set))]
    if ozgaruvchan:
        ball -= 25
        ogohlar.append(f"o'zgaruvchan sukut: {ozgaruvchan}")

    return max(0, ball), ogohlar


NAMUNALAR = [
    yubor_v1, yubor_v2, yubor_v3, formatla,
    sorted, len, print,
]


def yomon_namuna(a, b, c, d, e, tozala=True, qatiy=False, r=[]):
    ...


NAMUNALAR.append(yomon_namuna)

print(f"  {'Funksiya':<16} {'Ball':>6}  Ogohlantirishlar")
print("  " + "─" * 66)
for f in NAMUNALAR:
    nom = getattr(f, "__name__", str(f))
    ball, ogohlar = imzoni_baholash(f)
    belgi = "✅" if ball >= 85 else ("⚠️" if ball >= 60 else "❌")
    print(f"  {belgi} {nom:<14} {ball:>5}  {ogohlar[0] if ogohlar else '—'}")
    for o in ogohlar[1:]:
        print(f"  {'':<22} {o}")

Natijaning muhim qismi:

text
=== 4. Bir funksiyani uch xil loyihalash ===
  Chaqiruv                                           v1    v2    v3
  ──────────────────────────────────────────────────────────────────────
  yubor("a@x", "Mavzu", "Matn", True, False, (), (   ✅     ❌     ❌
  yubor("a@x", "Mavzu", "Matn", html=True)           ❌    ✅    ✅
  yubor(kimga="a@x", mavzu="M", matn="T")            ❌     ✅     ❌

=== 6. Imzo sifatini baholash ===
  Funksiya           Ball  Ogohlantirishlar
  ──────────────────────────────────────────────────────────────────
  ⚠️ yubor_v1          80  7 pozitsion parametr (4 dan ko'p)
  ✅ yubor_v2         100  —
  ✅ yubor_v3         100  —
  ✅ formatla         100  —
  ❌ yomon_namuna       0  bool pozitsion bo'lishi mumkin: ['tozala', 'qatiy']
                         8 pozitsion parametr (4 dan ko'p)
                          o'zgaruvchan sukut: ['r']

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

Misol 4 — Amaliy: kutubxona API

python
"""To'liq kutubxona — / va * bilan loyihalangan."""

import inspect
import re
from dataclasses import dataclass, field
from enum import Enum

print("=== Matn qayta ishlash kutubxonasi ===\n")


class Registr(Enum):
    SAQLASH = "saqlash"
    KICHIK = "kichik"
    KATTA = "katta"
    SARLAVHA = "sarlavha"


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


# ─────────────────────────────────────────────
# Asosiy funksiyalar — barchasi / va * bilan
# ─────────────────────────────────────────────

def tozala(matn, /, *,
           bosh_joylar=True,
           takroriy_joylar=True,
           registr=Registr.SAQLASH,
           belgilar=None):
    """Matnni tozalaydi.

    matn — faqat pozitsion (nomi ichki tafsilot)
    qolgan hammasi — faqat nomli (o'qiladigan chaqiruv)
    """
    if belgilar:
        matn = matn.translate(str.maketrans("", "", belgilar))
    if takroriy_joylar:
        matn = re.sub(r"\s+", " ", matn)
    if bosh_joylar:
        matn = matn.strip()

    if registr is Registr.KICHIK:
        matn = matn.casefold()
    elif registr is Registr.KATTA:
        matn = matn.upper()
    elif registr is Registr.SARLAVHA:
        matn = " ".join(s.capitalize() for s in matn.split())

    return matn


def kes(matn, uzunlik, /, *, oxiri="…", sozlarni_saqlash=True):
    """Matnni belgilangan uzunlikka kesadi."""
    if len(matn) <= uzunlik:
        return matn
    kesish_nuqtasi = uzunlik - len(oxiri)
    if kesish_nuqtasi <= 0:
        return oxiri[:uzunlik]
    kesilgan = matn[:kesish_nuqtasi]
    if sozlarni_saqlash and " " in kesilgan:
        kesilgan = kesilgan.rsplit(" ", 1)[0]
    return kesilgan + oxiri


def joyla(matn, kenglik, /, *,
          tekislash=Tekislash.CHAP,
          toldirish=" ",
          kesish=True):
    """Matnni belgilangan kenglikka joylaydi."""
    if kesish and len(matn) > kenglik:
        matn = kes(matn, kenglik)
    return f"{matn:{toldirish}{tekislash.value}{kenglik}}"


def bol(matn, /, *, ajratgich=None, chegara=-1, bosh_tashla=True):
    """Matnni bo'laklarga ajratadi."""
    qismlar = matn.split(ajratgich, chegara)
    if bosh_tashla:
        qismlar = [q for q in qismlar if q.strip()]
    return qismlar


def almashtir(matn, eski, yangi, /, *,
              soni=-1,
              registr_farqi=True,
              butun_soz=False):
    """Matnda almashtirish."""
    if butun_soz:
        naqsh = rf"\b{re.escape(eski)}\b"
    else:
        naqsh = re.escape(eski)
    bayroqlar = 0 if registr_farqi else re.IGNORECASE
    return re.sub(naqsh, yangi, matn, count=0 if soni < 0 else soni,
                  flags=bayroqlar)


def ramka(matn, /, *,
          kenglik=None,
          uslub="oddiy",
          sarlavha=None,
          tekislash=Tekislash.CHAP):
    """Matnni ramkaga oladi."""
    USLUBLAR = {
        "oddiy": "─│┌┐└┘",
        "qalin": "━┃┏┓┗┛",
        "ikki":  "═║╔╗╚╝",
        "nuqta": "╌╎┌┐└┘",
    }
    h, v, yc, yo_, pc, po = USLUBLAR[uslub]

    qatorlar = matn.splitlines() or [""]
    kenglik = kenglik or max(len(q) for q in qatorlar) + 2
    ichki = kenglik - 2

    natija = []
    if sarlavha:
        s = f" {kes(sarlavha, ichki - 2)} "
        natija.append(yc + s.center(ichki, h) + yo_)
    else:
        natija.append(yc + h * ichki + yo_)

    for q in qatorlar:
        natija.append(v + joyla(q, ichki, tekislash=tekislash) + v)

    natija.append(pc + h * ichki + po)
    return "\n".join(natija)


# ═══ NAMOYISH ═══

XOM = "   Salom,    DUNYO!   Bu   —  sinov    matni.   "

print("=== 1. tozala ===\n")
print(f"  Xom: {XOM!r}\n")

VARIANTLAR = [
    ("tozala(m)", {}),
    ("tozala(m, registr=Registr.KICHIK)", {"registr": Registr.KICHIK}),
    ("tozala(m, registr=Registr.SARLAVHA)", {"registr": Registr.SARLAVHA}),
    ("tozala(m, belgilar=',.!—')", {"belgilar": ",.!—"}),
    ("tozala(m, takroriy_joylar=False)", {"takroriy_joylar": False}),
]

for kod, kwargs in VARIANTLAR:
    print(f"  {kod:<40}")
    print(f"    → {tozala(XOM, **kwargs)!r}")


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

MATN = "Python — kuchli va oddiy dasturlash tili"
print(f"  Matn: {MATN!r} ({len(MATN)} belgi)\n")

for uzunlik in [20, 30, 15]:
    for saqlash in [True, False]:
        natija = kes(MATN, uzunlik, sozlarni_saqlash=saqlash)
        print(f"  kes(m, {uzunlik}, sozlarni_saqlash={saqlash!s:<5}) "
              f"→ {natija!r}")
    print()


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

for uslub in ["oddiy", "qalin", "ikki", "nuqta"]:
    print(ramka(
        "Salom, dunyo!\nBu — ikkinchi qator.",
        kenglik=34,
        uslub=uslub,
        sarlavha=uslub.upper(),
        tekislash=Tekislash.MARKAZ,
    ))
    print()


print("=== 4. almashtir ===\n")

MATN2 = "Python python PYTHON pythonic"
print(f"  Matn: {MATN2!r}\n")

VARIANTLAR = [
    ("almashtir(m, 'python', 'Py')", ("python", "Py"), {}),
    ("almashtir(m, 'python', 'Py', registr_farqi=False)",
     ("python", "Py"), {"registr_farqi": False}),
    ("almashtir(m, 'python', 'Py', registr_farqi=False, butun_soz=True)",
     ("python", "Py"), {"registr_farqi": False, "butun_soz": True}),
    ("almashtir(m, 'python', 'Py', registr_farqi=False, soni=1)",
     ("python", "Py"), {"registr_farqi": False, "soni": 1}),
]

for kod, args, kwargs in VARIANTLAR:
    print(f"  {kod}")
    print(f"    → {almashtir(MATN2, *args, **kwargs)!r}\n")


print("=== 5. ⭐ API dizayni tahlili ===\n")

FUNKSIYALAR = [tozala, kes, joyla, bol, almashtir, ramka]

print(f"  {'Funksiya':<12} {'Poz.':>5} {'Nomli':>6}  Imzo")
print("  " + "─" * 76)
for f in FUNKSIYALAR:
    sig = inspect.signature(f)
    ps = sig.parameters.values()
    poz = sum(1 for p in ps if p.kind is p.POSITIONAL_ONLY)
    nomli = sum(1 for p in ps if p.kind is p.KEYWORD_ONLY)
    imzo = str(sig)
    if len(imzo) > 50:
        imzo = imzo[:48] + "…"
    print(f"  {f.__name__:<12} {poz:>5} {nomli:>6}  {imzo}")

print(f"""
  ⭐ Barcha funksiyalarda bir xil naqsh:

     def f(asosiy..., /, *, sozlama1=..., sozlama2=...)

     • Asosiy argumentlar — faqat pozitsion
       (nomlarini keyinchalik o'zgartirish mumkin)

     • Sozlamalar — faqat nomli
       (chaqiruv o'z-o'zini hujjatlaydi, yangi qo'shish xavfsiz)
""")


print("=== 6. Noto'g'ri chaqiruvlar ===\n")

XATOLAR = [
    ("tozala(matn='x')",            lambda: tozala(matn="x")),
    ("kes('abc', uzunlik=2)",       lambda: kes("abc", uzunlik=2)),
    ("kes('abcdef', 3, '...')",     lambda: kes("abcdef", 3, "...")),
    ("joyla('x', 10, Tekislash.ONG)", lambda: joyla("x", 10, Tekislash.ONG)),
    ("bol('a b', ' ')",             lambda: bol("a b", " ")),
]

for kod, f in XATOLAR:
    try:
        natija = f"✅ {f()!r}"
    except TypeError as x:
        natija = f"❌ {str(x)[:52]}"
    print(f"  {kod:<34} {natija}")

print("""
  ⭐ Har bir xato DARHOL va ANIQ:
     • Foydalanuvchi to'g'ri shaklni o'rganadi
     • Jimgina noto'g'ri natija bo'lmaydi
""")


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


def tozala_v2(matn, /, *,
              bosh_joylar=True,
              takroriy_joylar=True,
              registr=Registr.SAQLASH,
              belgilar=None,
              # ⭐ YANGI parametrlar — hech narsa buzilmaydi
              normalizatsiya=None,
              apostrof_birlashtirish=False,
              maksimal_uzunlik=None):
    """v2 — uchta yangi parametr qo'shildi."""
    natija = tozala(matn, bosh_joylar=bosh_joylar,
                    takroriy_joylar=takroriy_joylar,
                    registr=registr, belgilar=belgilar)
    if apostrof_birlashtirish:
        for a in "ʻʼ''`":
            natija = natija.replace(a, "'")
    if normalizatsiya:
        import unicodedata
        natija = unicodedata.normalize(normalizatsiya, natija)
    if maksimal_uzunlik:
        natija = kes(natija, maksimal_uzunlik)
    return natija


print(f"  Eski chaqiruvlar v2 da ham ishlaydi:\n")
ESKI = [
    ("tozala(m)", {}),
    ("tozala(m, registr=Registr.KICHIK)", {"registr": Registr.KICHIK}),
    ("tozala(m, belgilar=',.')", {"belgilar": ",."}),
]

for kod, kwargs in ESKI:
    v1 = tozala(XOM, **kwargs)
    v2 = tozala_v2(XOM, **kwargs)
    belgi = "✅" if v1 == v2 else "❌"
    print(f"  {belgi} {kod:<40} {v1[:26]!r}")

print(f"\n  Yangi imkoniyatlar:")
print(f"    tozala_v2(m, apostrof_birlashtirish=True, maksimal_uzunlik=20)")
print(f"      → {tozala_v2('  Oʻzbekiston  Respublikasi  ', apostrof_birlashtirish=True, maksimal_uzunlik=20)!r}")

print("""
  ⭐ * dan keyin yangi parametr qo'shish — MUTLAQO xavfsiz:
     • Tartib muhim emas
     • Eski chaqiruvlar buzilmaydi
     • Sukut qiymatlar orqaga moslikni saqlaydi
""")

Natijaning muhim qismi:

text
=== 3. ramka ===

┌──────────── ODDIY ─────────────┐
│         Salom, dunyo!        │
│    Bu — ikkinchi qator.      │
└────────────────────────────────┘

╔═════════════ IKKI ═════════════╗
║         Salom, dunyo!        ║
║    Bu — ikkinchi qator.      ║
╚════════════════════════════════╝

=== 5. ⭐ API dizayni tahlili ===
  Funksiya      Poz.  Nomli  Imzo
  ────────────────────────────────────────────────────────────────────────────
  tozala           1      4  (matn, /, *, bosh_joylar=True, takroriy_joyl…
  kes              2      2  (matn, uzunlik, /, *, oxiri='…', sozlarni_s…
  joyla            2      3  (matn, kenglik, /, *, tekislash=<Tekislash.C…
  almashtir        3      3  (matn, eski, yangi, /, *, soni=-1, registr_f…

=== 6. Noto'g'ri chaqiruvlar ===
  tozala(matn='x')                   ❌ tozala() got some positional-only arg
  kes('abcdef', 3, '...')            ❌ kes() takes 2 positional arguments but

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


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

Noto'g'ri fikr To'g'risi
"/ va * — ekzotik" Standart kutubxonada keng ishlatiladi
"/ faqat C funksiyalarida" Python 3.8+ da har qanday funksiyada
"* — *args bilan bir xil" * argument yig'maydi, faqat chegara qo'yadi
"* dan keyin sukutlar oxirida bo'lishi kerak" Tartib erkin
"/ qo'shish xavfsiz" Buzuvchi — nomli chaqiruvlar
"* qo'shish xavfsiz" Buzuvchi — pozitsion chaqiruvlar
"/ faqat estetika" **kwargs bilan nom to'qnashuvini hal qiladi
"Nomli argument har doim yaxshiroq" Pozitsion tezroq va ba'zan tabiiy
"def f(a, *) mumkin" SyntaxError — * dan keyin parametr kerak

6. Keng tarqalgan xatolar va yechimlari

1. Bool parametr * siz

python
def sarala(r, teskari=False): ...       # ⚠️ sarala(r, True)
def sarala(r, *, teskari=False): ...    # ✅

2. Mavjud funksiyaga * qo'shish

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

3. / dan keyin nomli chaqirish

python
def f(a, /): ...
f(a=1)                                  # ❌
f(1)                                    # ✅

4. * dan keyin parametr yo'q

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

5. / * dan keyin

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

6. **kwargs bilan nom to'qnashuvi

python
def f(nom, **kw): ...
f("x", nom="y")                         # ❌
def f(nom, /, **kw): ...                # ✅

7. Ko'p sukutli pozitsion

python
def f(a, b=1, c=2, d=3, e=4): ...       # ⚠️ f(x, 1, 2, 3, 4)
def f(a, *, b=1, c=2, d=3, e=4): ...    # ✅

8. / ma'noli nom uchun

python
def ochish(fayl_yoli, /): ...           # ⚠️ nom foydali edi
def ochish(fayl_yoli): ...              # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 7.2, 7.4, 7.5-darslar (o'tilgan): argumentlar, nomli, *args
  • 8-qism: metodlar, self, dataclass
  • 10-qism: dekoratorlar, functools
  • 14-dars: tur ko'rsatkichlari, ParamSpec
  • inspect: imzo tahlili
  • PEP 570 (/), PEP 3102 (*)
  • API dizayni: semantik versiyalash, orqaga moslik

8. Eng yaxshi amaliyotlar

  1. Sukut naqsh: def f(asosiy, /, *, sozlama=None). Nom yopiq, sozlamalar nomli.

  2. Bool parametrni doim * dan keyin. Bu — eng muhim qoida.

  3. 3+ ixtiyoriy sozlama — * dan keyin. Tartibni eslash shart emas.

  4. Nomi ma'nosiz parametrlarga /. obj, x, iterable, self.

  5. **kwargs bilan / ishlating. Nom to'qnashuvini oldini oladi.

  6. Boshidan to'g'ri loyihalang. / yoki * qo'shish — buzuvchi o'zgarish.

  7. Ma'noli nomlarga / qo'ymang. fayl_yoli=, foydalanuvchi_id= foydali.

  8. inspect.signature bilan tekshiring. Imzo kutilganidek ekanini.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
def f(a, /, b, *, c): return a, b, c
def g(a, *, b=1, c): return a, b, c
def h(a, /, **kw): return a, kw

1.  print(f(1, 2, c=3))
2.  print(f(1, b=2, c=3))
3.  f(a=1, b=2, c=3)
4.  f(1, 2, 3)
5.  print(g(1, c=3))
6.  print(g(1, c=3, b=2))
7.  g(1, 2, 3)
8.  print(h(1, a=2))
9.  print(h(1, x=2, y=3))
10. def k(a, *): pass
11. def m(a, *, b, /): pass
12. import inspect; print(inspect.signature(len))
Javoblar
  1. (1, 2, 3)
  2. (1, 2, 3)
  3. TypeError — a faqat pozitsion
  4. TypeError — c faqat nomli
  5. (1, 1, 3)
  6. (1, 2, 3)
  7. TypeError — b va c faqat nomli
  8. (1, {'a': 2}) — / tufayli
  9. (1, {'x': 2, 'y': 3})
  10. SyntaxError — * dan keyin parametr kerak
  11. SyntaxError — / * dan oldin
  12. (obj, /)

Vazifa 2: Xatolarni tuzating

python
1.  def sarala(r, teskari=False, barqaror=True): ...
2.  def f(a, *): ...
3.  def f(a, *, b, /): ...
4.  def f(nom, **kwargs): ...   # nom kaliti kerak bo'lishi mumkin
5.  def f(a, b=1, c=2, d=3, e=4, g=5): ...
6.  def hisobla(malumot, True, False): ...
7.  # v1: def f(a, b)  →  v2: def f(a, *, b)
8.  def ochish(fayl_yoli, /, rejim="r"): ...
Javoblar
python
1.  def sarala(r, /, *, teskari=False, barqaror=True): ...
2.  def f(a, *, b): ...
3.  def f(a, /, *, b): ...
4.  def f(nom, /, **kwargs): ...
5.  def f(a, *, b=1, c=2, d=3, e=4, g=5): ...
6.  def hisobla(malumot, /, *, tozala=True, qatiy=False): ...
7.  Deprecation davri bilan: def f(a, b=None, *, yangi_b=None)
8.  def ochish(fayl_yoli, *, rejim="r"): ...   # nom ma'noli, / kerak emas

Vazifa 3: API refaktoring

Berilgan funksiyalarni qayta loyihalang (/ va * bilan):

python
def yubor(kimga, mavzu, matn, html, muhim, nusxa, ilova, urinishlar)
def qidir(matn, naqsh, katta_kichik, butun_soz, teskari, chegara)
def chiz(x, y, kenglik, balandlik, rang, ramka, toldirish, shaffof)
def ulan(host, port, foydalanuvchi, parol, ssl, timeout, pool)

Har biri uchun:

  1. Qaysi parametrlar / dan oldin
  2. Qaysi parametrlar * dan keyin
  3. Sabab
  4. inspect.signature bilan tekshiring

Vazifa 4: Imzo linteri

Vosita yozing:

  1. Modul funksiyalarini skanerlaydi
  2. Har biri uchun ball (0-100) beradi
  3. Ogohlantirishlar:
    • Bool parametr * siz
    • 4+ pozitsion parametr
    • 3+ sukutli pozitsion
    • **kwargs bor, lekin / yo'q
    • O'zgaruvchan sukut
  4. Tuzatilgan imzo taklifini beradi
  5. Hisobot jadval ko'rinishida

Vazifa 5: Migratsiya vositasi

Dekorator yozing:

python
@imzo_migratsiyasi(eski="(a, b, c)", yangi="(a, /, *, b, c)")
def f(a, /, *, b, c): ...
  1. Eski chaqiruv shakllarini qabul qilsin
  2. DeprecationWarning bersin
  3. Yangi shaklga o'tkazsin
  4. inspect.signature yangi shaklni ko'rsatsin
  5. Bir necha versiyani qo'llab-quvvatlasin

Vazifa 6: Kutubxona loyihalash

To'liq kutubxona yozing (10+ funksiya):

  1. Barchasida asosiy, /, *, sozlamalar naqshi
  2. Enum bilan sozlamalar (bool o'rniga)
  3. Har biri uchun docstring va tur ko'rsatkichlari
  4. Kelajakdagi kengaytirishni sinab ko'ring
  5. Noto'g'ri chaqiruvlar uchun testlar
  6. inspect bilan API hisoboti

Vazifa 7: O'ylash

Nega Python / ni faqat 3.8 da qo'shdi, garchi C funksiyalari uni 20 yil ishlatgan bo'lsa ham?

Javob

Chunki muammo faqat vaqt o'tib ko'rindi.

Tarixiy holat:

C da yozilgan funksiyalar har doim faqat pozitsion edi:

python
len(obj=[1, 2])             # ❌ Python 2 da ham
abs(x=-5)                   # ❌

Sabab — texnik: C API (PyArg_ParseTuple) nomli argumentlarni qo'llab-quvvatlamasdi. Bu — cheklov edi, dizayn qarori emas.

Pythonda yozilgan funksiyalar esa har doim nomli chaqiruvni qabul qilardi:

python
def f(a): ...
f(a=1)                      # ✅ har doim ishlagan

Nomuvofiqlik:

python
len([1, 2])                 # ✅
len(obj=[1, 2])             # ❌

def mening_len(obj): return len(obj)
mening_len(obj=[1, 2])      # ✅  — nomuvofiq!

Yillar davomida bu "shunchaki shunday" deb qabul qilindi.

Muammo qachon ko'rindi:

1. Pure-Python qayta yozishlar.

Ba'zi C modullari Pythonda qayta yozildi (io, datetime, decimal). Ular endi nomli argumentni qabul qila boshladi — bu xatti-harakat o'zgarishi:

python
# C versiyasi
_datetime.date(year=2026, month=9, day=8)   # ❌

# Python versiyasi
datetime.date(year=2026, month=9, day=8)    # ✅  — farq!

2. Argument Clinic.

2013 da CPython ga Argument Clinic vositasi qo'shildi — u C funksiyalari uchun imzolarni avtomatik generatsiya qiladi. Endi C funksiyalari nomli argumentni qabul qila olardi.

Lekin ko'p funksiya uchun bu kerak emas edi:

python
len(obj=[1, 2])             # foydali emas, lekin endi mumkin?

Va obj nomi — ichki tafsilot. Uni API ga aylantirish istalmagan.

Shuning uchun / sintaksisi hujjatlarda paydo bo'ldi — imzoda "bu yerdan oldin faqat pozitsion" degan belgi.

3. **kwargs bilan to'qnashuv.

python
def f(nom, **kwargs): ...
f("x", nom="y")             # ❌ TypeError

Bu — real muammo. dict() uni maxsus C kodi bilan hal qilgan, lekin Python funksiyalari uchun yo'l yo'q edi.

4. Kutubxona mualliflari so'radi.

API dizaynerlari parametr nomlarini yopish imkonini so'ray boshladi — chunki nomni o'zgartirish orqaga moslikni buzardi.

PEP 570 (2018):

Yozuvchilar: Larry Hastings, Pablo Galindo, Mario Corchero, Eric N. Vander Weele.

Asosiy dalillar:

  1. Nomuvofiqlikni bartaraf etish — Python funksiyalari C funksiyalari kabi bo'la oladi
  2. Nomlarni yopish — API evolyutsiyasi uchun
  3. **kwargs to'qnashuvi — hal qilinadi
  4. Hujjatlar sintaksisini rasmiylashtirish — / allaqachon help() da ko'rinardi

Qarshi dalillar (muhokamada):

  • "Yana bir sintaksis — o'rganish narxi"
  • "_nom kelishuvi yetarli" (lekin u majburlamaydi)
  • "Kam ishlatiladi"

Nega 20 yil ketdi:

1. Muammo asta-sekin to'plandi.

Har bir sabab alohida kichik edi. Faqat birgalikda ular PEP ni oqladi.

2. Sintaksis tanlash qiyin edi.

Muqobil takliflar:

python
def f(a, b, __, c): ...     # __ ajratgich
def f(*, a, b; c): ...      # nuqtali vergul
@positional_only(2)         # dekorator
def f(a, b, c): ...

/ tanlandi, chunki u allaqachon hujjatlarda ishlatilardi (help() chiqishida).

3. * (PEP 3102, 2006) birinchi keldi.

Faqat nomli argumentlar 12 yil oldin qo'shilgan. / — uning simmetrik juftligi. Lekin * ning ehtiyoji aniqroq edi (bool argumentlar muammosi).

Bugungi holat:

python
# Python 3.8+ da to'liq nazorat
def f(a, /, b, *, c): ...

Standart kutubxona asta-sekin / qo'shmoqda — lekin faqat yangi funksiyalarga yoki / allaqachon amalda bo'lgan C funksiyalariga. Mavjud Python funksiyalariga qo'shish — buzuvchi o'zgarish.

Xulosa: bu — til evolyutsiyasining tipik namunasi. Muammo yillar davomida to'planadi, bir necha sabab birlashadi, keyin PEP paydo bo'ladi. Va yechim ko'pincha allaqachon amalda mavjud narsani rasmiylashtiradi — bu holda help() dagi / belgisini.

Nimani mustahkamlaydi: 2.2, 2.4, 2.6-bo'limlar.


Xulosa

Bu darsda / va * belgilarini o'rgandik.

Eng muhim uch fikr:

  1. * — bool argumentlarni o'qiladigan qiladi. sarala(r, True, False) o'rniga sarala(r, teskari=True). Va * dan keyin yangi parametr qo'shish mutlaqo xavfsiz — tartib ham, sukut qiymatlar tartibi ham muhim emas.

  2. / — parametr nomini ichki tafsilotga aylantiradi. Nomni keyinchalik o'zgartirish mumkin bo'ladi, va **kwargs bilan nom to'qnashuvi yo'qoladi (f("x", nom="y") ishlaydi).

  3. Sukut naqsh: def f(asosiy, /, *, sozlama=None). Bu — standart kutubxonaning naqshi (sorted, print, json.dumps). Lekin / yoki * ni mavjud funksiyaga qo'shish — buzuvchi o'zgarish, shuning uchun boshidan to'g'ri loyihalang.

Keyingi darsda return ni chuqur o'rganamiz: bir nechta qiymat, erta qaytish, None semantikasi va generator funksiyalari bilan farq.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
7.6-dars: Faqat pozitsion va faqat nomli argumentlar — IlmHamroh