IlmHamroh
Python kursi/Funksiyalar3/14-dars34 daqiqa
Mundarija (21)

7.3-dars: Standart qiymatlar va mashhur tuzoq

7-QISM — FUNKSIYALAR · 3-dars


1. Kirish va motivatsiya

Standart (sukut) qiymat funksiyani qulayroq qiladi:

python
def salomlash(ism, salom="Salom"):
    return f"{salom}, {ism}!"

salomlash("Aziz")                   # "Salom, Aziz!"
salomlash("Aziz", "Assalomu alaykum")   # "Assalomu alaykum, Aziz!"

Lekin bitta xato butun Python jamoasiga tanish:

python
def qosh(element, royxat=[]):
    royxat.append(element)
    return royxat

print(qosh(1))          # [1]
print(qosh(2))          # [1, 2]   ⚠️ nega?!
print(qosh(3))          # [1, 2, 3]  ⚠️

Har chaqiruvda yangi bo'sh ro'yxat kutilardi. Lekin bitta ro'yxat qayta ishlatilyapti.

Bu — Pythonning eng mashhur tuzog'i. Va u faqat ro'yxat bilan emas:

python
def f(d={}): ...                    # ⚠️
def f(s=set()): ...                 # ⚠️
def f(v=datetime.now()): ...        # ⚠️ vaqt QOTIB QOLADI
def f(x=[], y=x): ...               # ⚠️

Bu darsda:

  • Sukut qiymatlar sintaksisi va qoidalari
  • Mashhur tuzoq — nega shunday va qanday hal qilish
  • None naqshi va uning variantlari
  • Sentinel qiymatlar
  • Sukut qiymat qachon hisoblanadi
  • __defaults__ va __kwdefaults__

2. Nazariya — chuqur tushuntirish

2.1. Sintaksis va qoidalar

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

f(1)                    # (1, 2, 3)
f(1, 20)                # (1, 20, 3)
f(1, 20, 30)            # (1, 20, 30)
f(1, c=30)              # (1, 2, 30)

Sukut qiymatli parametrlar OXIRIDA:

python
def f(a=1, b): ...      # ❌ SyntaxError: non-default argument follows default argument
def f(a, b=1): ...      # ✅

Sabab: aks holda f(5) da 5 qaysi parametrga tegishli ekani noaniq bo'lardi.

* dan keyin cheklov yo'q (6-dars):

python
def f(a, *, b, c=1): ...    # ✅ b majburiy, c sukut bilan

Sukut qiymat sifatida nima bo'lishi mumkin:

python
def f(a=1): ...                     # son
def f(a="x"): ...                   # satr
def f(a=None): ...                  # None
def f(a=()): ...                    # bo'sh tuple
def f(a=frozenset()): ...           # frozenset
def f(a=CONSTANT): ...              # modul konstantasi
def f(a=hisobla()): ...             # ⚠️ funksiya chaqiruvi — ehtiyot bo'ling
def f(a=[]): ...                    # ⚠️ o'zgaruvchan — TUZOQ

2.2. Sukut qiymat QACHON hisoblanadi

Javob: funksiya ANIQLANGANDA, bir marta.

python
def f(x=hisobla()):
    return x

hisobla() — def qatori bajarilganda bir marta chaqiriladi. Chaqiruvlarda emas.

Namoyish:

python
chaqiruvlar = []

def qimmat():
    chaqiruvlar.append(1)
    return len(chaqiruvlar)

def f(x=qimmat()):
    return x

print(chaqiruvlar)      # [1]  ← def bajarilganda chaqirilgan

f(); f(); f()
print(chaqiruvlar)      # [1]  ← ko'proq chaqirilmadi

Bu — vaqt bilan bog'liq tuzoq:

python
from datetime import datetime

def yozuv(matn, vaqt=datetime.now()):       # ⚠️
    return f"[{vaqt}] {matn}"

yozuv("birinchi")       # [2026-09-08 10:00:00] birinchi
# ... 3 soatdan keyin
yozuv("ikkinchi")       # [2026-09-08 10:00:00] ikkinchi  ⚠️ ESKI VAQT

Yechim:

python
def yozuv(matn, vaqt=None):
    if vaqt is None:
        vaqt = datetime.now()               # ✅ har chaqiruvda
    return f"[{vaqt}] {matn}"

Sukut qiymat funksiya obyektida saqlanadi:

python
def f(a=1, b=[]): ...

f.__defaults__          # (1, [])

Bu — bitta obyekt. Har chaqiruvda o'sha obyekt ishlatiladi.

Sukut qiymatni ishlash vaqtida o'zgartirish:

python
def f(a=1): return a

f()                     # 1
f.__defaults__ = (99,)
f()                     # 99  ⚠️ ishlaydi, lekin qilmang

2.3. Mashhur tuzoq

python
def qosh(element, royxat=[]):
    royxat.append(element)
    return royxat

Nima sodir bo'ladi:

  1. def bajarilganda [] bir marta yaratiladi
  2. U qosh.__defaults__ da saqlanadi
  3. Har chaqiruvda (royxat berilmasa) o'sha ro'yxat ishlatiladi
  4. append uni o'zgartiradi
  5. Keyingi chaqiruv o'zgargan ro'yxatni ko'radi
python
qosh(1)                 # [1]
qosh.__defaults__       # ([1],)  ← sukut qiymat O'ZGARDI!
qosh(2)                 # [1, 2]
qosh.__defaults__       # ([1, 2],)

Barcha o'zgaruvchan turlar uchun:

python
def f(d={}): ...        # dict
def f(s=set()): ...     # set
def f(b=bytearray()): ...
def f(o=MeningSinf()): ...      # o'zgaruvchan obyekt

O'zgarmas turlar xavfsiz:

python
def f(a=1): ...         # int
def f(s="x"): ...       # str
def f(t=()): ...        # tuple
def f(f=frozenset()): ...
def f(n=None): ...      # None

Lekin tuple ichida o'zgaruvchan bo'lsa:

python
def f(t=(1, [])):       # ⚠️ ichidagi ro'yxat umumiy
    t[1].append(1)

2.4. Yechimlar

1. None naqshi (standart):

python
def qosh(element, royxat=None):
    if royxat is None:
        royxat = []
    royxat.append(element)
    return royxat

if royxat is None, if not royxat emas:

python
def f(r=None):
    if not r:               # ⚠️ bo'sh ro'yxat ham None kabi qaraladi
        r = [0]

f([])                       # [0]  ⚠️ foydalanuvchi bo'sh ro'yxat berdi!

is None — aniq va to'g'ri.

Qisqa shakl:

python
def f(r=None):
    r = [] if r is None else r          # ✅
    r = r if r is not None else []      # ✅
    r = r or []                         # ⚠️ bo'sh ro'yxat almashtiriladi

2. O'zgarmas sukut:

python
def qosh(element, royxat=()):
    return [*royxat, element]           # ✅ yangi ro'yxat

Bu — argumentni ham o'zgartirmaydi (7.2-dars).

3. Ichkarida nusxa:

python
def qayta_ishla(r=None):
    r = list(r or [])                   # ✅ nusxa
    r.sort()
    return r

4. Sentinel obyekt (None ham yaroqli qiymat bo'lsa):

python
YOQ = object()

def f(x=YOQ):
    if x is YOQ:
        x = hisobla_sukut()
    ...

f()                     # sukut hisoblanadi
f(None)                 # ⭐ None ham yaroqli qiymat sifatida uzatiladi

Amaliy misol:

python
def d_ol(d, kalit, sukut=YOQ):
    """None ni ham yaroqli qiymat sifatida qaytaradi."""
    if kalit in d:
        return d[kalit]
    if sukut is YOQ:
        raise KeyError(kalit)
    return sukut

Sentinel uchun variantlar:

python
YOQ = object()                          # ✅ oddiy
_YOQ = object()                         # ✅ modul ichida

class _Yoq:                             # ✅ repr yaxshiroq
    def __repr__(self): return "<YOQ>"
YOQ = _Yoq()

from enum import Enum                   # ✅ eng aniq
class _Sentinel(Enum):
    YOQ = object()
YOQ = _Sentinel.YOQ

5. Dekorator bilan (kam ishlatiladi):

python
def yangi_sukut(**sukutlar):
    def dekorator(f):
        @wraps(f)
        def ichki(*args, **kwargs):
            for nom, yaratuvchi in sukutlar.items():
                kwargs.setdefault(nom, yaratuvchi())
            return f(*args, **kwargs)
        return ichki
    return dekorator


@yangi_sukut(royxat=list)
def qosh(element, royxat):
    royxat.append(element)
    return royxat

2.5. Qachon o'zgaruvchan sukut FOYDALI

Tuzoq — ba'zan xususiyat:

1. Kesh (memoizatsiya):

python
def fib(n, kesh={0: 0, 1: 1}):
    if n not in kesh:
        kesh[n] = fib(n - 1, kesh) + fib(n - 2, kesh)
    return kesh[n]

fib(100)                # tez — kesh saqlanadi

Lekin functools.lru_cache aniqroq:

python
@lru_cache(maxsize=None)
def fib(n):
    return n if n < 2 else fib(n - 1) + fib(n - 2)

2. Chaqiruvlarni sanash:

python
def f(hisob=[0]):
    hisob[0] += 1
    return hisob[0]

Funksiya atributi aniqroq:

python
def f():
    f.hisob += 1
    return f.hisob
f.hisob = 0

3. Tezlik uchun oldindan hisoblash:

python
def tozala(matn, jadval=str.maketrans("", "", ".,!?")):
    return matn.translate(jadval)       # ⚠️ jadval bir marta yaratiladi

Modul konstantasi aniqroq:

python
JADVAL = str.maketrans("", "", ".,!?")

def tozala(matn):
    return matn.translate(JADVAL)

4. Lokal nomni tezlashtirish (mikro-optimallashtirish):

python
def f(r, _len=len, _range=range):       # ⚠️ eski hiyla
    for i in _range(_len(r)): ...

Bu — global qidiruvni lokalga aylantiradi. Zamonaviy Pythonda foyda kichik va kod o'qilishi yomonlashadi.

Xulosa: o'zgaruvchan sukut qiymat ataylab ishlatilishi mumkin, lekin deyarli har doim aniqroq muqobil bor.

2.6. __defaults__ va __kwdefaults__

python
def f(a, b=2, c=3, *, d=4, e=5):
    ...

f.__defaults__          # (2, 3)      — pozitsion parametrlar sukuti
f.__kwdefaults__        # {'d': 4, 'e': 5}  — faqat nomli

__defaults__ — oxiridan bog'lanadi:

python
def f(a, b, c=3):
    ...
f.__defaults__          # (3,)   ← faqat c

namedtuple(defaults=...) bilan bir xil mantiq (6.6-dars).

inspect bilan aniqroq:

python
import inspect

sig = inspect.signature(f)
for nom, p in sig.parameters.items():
    print(nom, p.default, p.kind)
text
a <class 'inspect._empty'> POSITIONAL_OR_KEYWORD
b 2 POSITIONAL_OR_KEYWORD
c 3 POSITIONAL_OR_KEYWORD
d 4 KEYWORD_ONLY

Sukut qiymatlarni tekshirish vositasi:

python
def ozgaruvchan_sukutlarni_top(f):
    """O'zgaruvchan sukut qiymatlarni topadi."""
    OZGARUVCHAN = (list, dict, set, bytearray)
    natija = []
    for nom, p in inspect.signature(f).parameters.items():
        if p.default is not inspect.Parameter.empty:
            if isinstance(p.default, OZGARUVCHAN):
                natija.append((nom, p.default))
    return natija

Linterlar (ruff, pylint, flake8-bugbear) buni avtomatik topadi:

B006 Do not use mutable data structures for argument defaults

2.7. Sukut qiymatlar dizayni

1. Sukut qiymat — eng ko'p ishlatiladigan holat:

python
def ochish(yol, rejim="r", kodlash="utf-8"): ...    # ✅
def ochish(yol, rejim, kodlash): ...                # ⚠️ har safar yozish kerak

2. Sukut qiymat xavfsiz bo'lsin:

python
def ochish(yol, rejim="w"): ...         # ⚠️ tasodifan yozib yuborish
def ochish(yol, rejim="r"): ...         # ✅ o'qish xavfsizroq

3. Sukut qiymat oldindan aytiladigan bo'lsin:

python
def sarala(r, kamayish=False): ...      # ✅ tabiiy
def sarala(r, kamayish=True): ...       # ⚠️ kutilmagan

4. None — "ko'rsatilmagan" ma'nosida:

python
def qidir(matn, chegara=None):
    """chegara=None — cheklov yo'q."""
    ...

5. Bir-biriga bog'liq sukutlar:

python
def yarat(kenglik=None, balandlik=None):
    if kenglik is None and balandlik is None:
        kenglik, balandlik = 80, 24
    elif kenglik is None:
        kenglik = balandlik * 3
    elif balandlik is None:
        balandlik = kenglik // 3
    ...

Sukut qiymat boshqa parametrga tayana olmaydi:

python
def f(a, b=a): ...                      # ❌ NameError: name 'a' is not defined
def f(a, b=None):                       # ✅
    b = a if b is None else b

3. Tez ma'lumotnoma

Sintaksis

python
def f(a, b=2, c=3): ...         sukutlar OXIRIDA
def f(a=1, b): ...              ❌ SyntaxError
def f(a, *, b, c=1): ...        ✅ * dan keyin cheklov yo'q
def f(a, b=a): ...              ❌ boshqa parametrga tayanolmaydi

Sukut qiymat DEF paytida bir marta hisoblanadi

python
def f(x=qimmat()): ...          qimmat() BIR MARTA — def qatorida
def f(v=datetime.now()): ...    ⚠️ vaqt QOTIB QOLADI
f.__defaults__                  saqlangan obyektlar

MASHHUR TUZOQ

python
def f(r=[]):                    ❌ BITTA ro'yxat barcha chaqiruvga
    r.append(1); return r
f() → [1];  f() → [1,1];  f() → [1,1,1]

✅ Yechimlar:
def f(r=None): r = [] if r is None else r
def f(r=()): return [*r, x]
def f(r=None): r = list(r or [])
YOQ = object(); def f(x=YOQ): ...      (None ham yaroqli bo'lsa)

is None, not r emas

python
if r is None: r = []        ✅
if not r: r = []            ⚠️ bo'sh ro'yxat ham almashtiriladi
r = r or []                 ⚠️ bir xil muammo

Xavfsiz sukut turlari

✅ int, float, str, bool, None, tuple, frozenset, bytes
⚠️ list, dict, set, bytearray, o'zgaruvchan obyektlar
⚠️ (1, [])  — tuple ichida o'zgaruvchan

Tekshirish

python
f.__defaults__          pozitsion sukutlar (OXIRIDAN)
f.__kwdefaults__        faqat nomli sukutlar
inspect.signature(f)    to'liq
ruff / pylint: B006     avtomatik topadi

4. Batafsil misollar

Misol 1 — Tuzoq va uning mexanizmi

python
"""Mashhur tuzoq — nima uchun va qanday hal qilish."""

print("=== 1. ⭐ Tuzoq ===")


def qosh_yomon(element, royxat=[]):
    royxat.append(element)
    return royxat


print(f"  def qosh(element, royxat=[]):\n")
for i in range(1, 5):
    print(f"    qosh({i})  →  {qosh_yomon(i)}")

print(f"\n  ⚠️ Har chaqiruvda yangi ro'yxat KUTILARDI, lekin bitta ishlatildi")


print("\n=== 2. Sabab: __defaults__ ===")


def qosh(element, royxat=[]):
    royxat.append(element)
    return royxat


print(f"  Boshida:")
print(f"    qosh.__defaults__ = {qosh.__defaults__}")
print(f"    id(qosh.__defaults__[0]) = {id(qosh.__defaults__[0])}\n")

for i in range(1, 4):
    natija = qosh(i)
    print(f"    qosh({i}) → {natija}")
    print(f"      __defaults__ = {qosh.__defaults__}")
    print(f"      natija is __defaults__[0]: {natija is qosh.__defaults__[0]}")

print("""
  ⭐ Sukut qiymat funksiya OBYEKTIDA saqlanadi.
     Har chaqiruvda O'SHA obyekt ishlatiladi.
     append uni o'zgartiradi.
""")


print("\n=== 3. Sukut qiymat QACHON hisoblanadi ===")

chaqiruvlar = []


def qimmat():
    chaqiruvlar.append(len(chaqiruvlar) + 1)
    print(f"      qimmat() chaqirildi (#{len(chaqiruvlar)})")
    return len(chaqiruvlar)


print(f"  def f(x=qimmat()):")


def f(x=qimmat()):
    return x


print(f"    ↑ def bajarilganda chaqirildi\n")
print(f"  Chaqiruvlar:")
for _ in range(3):
    print(f"    f() → {f()}")

print(f"\n  qimmat() jami chaqirilishi: {len(chaqiruvlar)}")
print(f"  ⭐ BIR MARTA — def qatorida")


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

from datetime import datetime
import time


def yozuv_yomon(matn, vaqt=datetime.now()):
    return f"[{vaqt:%H:%M:%S.%f}] {matn}"


def yozuv_yaxshi(matn, vaqt=None):
    vaqt = vaqt or datetime.now()
    return f"[{vaqt:%H:%M:%S.%f}] {matn}"


print(f"  ❌ vaqt=datetime.now():")
for i in range(3):
    print(f"    {yozuv_yomon(f'xabar {i}')}")
    time.sleep(0.05)

print(f"\n  ✅ vaqt=None + ichkarida:")
for i in range(3):
    print(f"    {yozuv_yaxshi(f'xabar {i}')}")
    time.sleep(0.05)


print("\n=== 5. Barcha o'zgaruvchan turlar ===")


def f_list(x, r=[]):
    r.append(x); return r


def f_dict(x, d={}):
    d[x] = x * 2; return d


def f_set(x, s=set()):
    s.add(x); return s


def f_bytearray(x, b=bytearray()):
    b.append(x); return b


TURLAR = [
    ("list",        f_list,         [1, 2, 3]),
    ("dict",        f_dict,         [1, 2, 3]),
    ("set",         f_set,          [1, 2, 3]),
    ("bytearray",   f_bytearray,    [65, 66, 67]),
]

print(f"  {'Tur':<12} {'1-chaqiruv':<18} {'2-chaqiruv':<22} {'3-chaqiruv'}")
print("  " + "─" * 72)
for nom, f, args in TURLAR:
    natijalar = [str(f(a)) for a in args]
    print(f"  {nom:<12} {natijalar[0]:<18} {natijalar[1]:<22} {natijalar[2]}")

print(f"\n  ✅ O'zgarmas turlar xavfsiz:")


def f_int(x, n=0):
    n += x; return n


def f_str(x, s=""):
    s += str(x); return s


def f_tuple(x, t=()):
    t = t + (x,); return t


for nom, f in [("int", f_int), ("str", f_str), ("tuple", f_tuple)]:
    natijalar = [str(f(i)) for i in [1, 2, 3]]
    print(f"    {nom:<8} {' → '.join(natijalar)}")

print(f"\n  ⚠️ Tuple ICHIDA o'zgaruvchan:")


def f_tuple_ichida(x, t=(1, [])):
    t[1].append(x)
    return t


for i in [1, 2, 3]:
    print(f"    f({i}) → {f_tuple_ichida(i)}")


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


def y1(element, royxat=None):
    """None naqshi (standart)."""
    if royxat is None:
        royxat = []
    royxat.append(element)
    return royxat


def y2(element, royxat=()):
    """O'zgarmas sukut."""
    return [*royxat, element]


def y3(element, royxat=None):
    """Ichkarida nusxa."""
    royxat = list(royxat or [])
    royxat.append(element)
    return royxat


YOQ = object()


def y4(element, royxat=YOQ):
    """Sentinel — None ham yaroqli qiymat bo'lsa."""
    if royxat is YOQ:
        royxat = []
    elif royxat is None:
        royxat = ["(None berildi)"]
    else:
        royxat = list(royxat)
    royxat.append(element)
    return royxat


YECHIMLAR = [
    ("y1: None naqshi",     y1),
    ("y2: () sukut",        y2),
    ("y3: nusxa",           y3),
    ("y4: sentinel",        y4),
]

print(f"  {'Yechim':<22} {'f(1)':<12} {'f(2)':<12} {'f(3)'}")
print("  " + "─" * 58)
for nom, f in YECHIMLAR:
    natijalar = [str(f(i)) for i in [1, 2, 3]]
    print(f"  {nom:<22} {natijalar[0]:<12} {natijalar[1]:<12} {natijalar[2]}")

print(f"\n  Sentinel — None bilan farq:")
print(f"    y4(1)        → {y4(1)}")
print(f"    y4(1, None)  → {y4(1, None)}   ⭐ None ham qabul qilinadi")


print("\n=== 7. ⚠️ is None vs not r ===")


def yomon_tekshiruv(r=None):
    if not r:                   # ⚠️
        r = ["sukut"]
    return r


def yaxshi_tekshiruv(r=None):
    if r is None:               # ✅
        r = ["sukut"]
    return r


SINOVLAR = [None, [], [1, 2], 0, "", {}]

print(f"  {'Kirish':<12} {'not r bilan':<24} {'is None bilan'}")
print("  " + "─" * 60)
for kirish in SINOVLAR:
    a = yomon_tekshiruv(kirish)
    b = yaxshi_tekshiruv(kirish)
    belgi = "⚠️" if a != b else "  "
    print(f"  {str(kirish):<12} {str(a):<24} {belgi} {b}")

print("""
  ⚠️ `not r` bo'sh ro'yxat, 0, "" ni ham None kabi qaraydi.
     Foydalanuvchi ATAYLAB bo'sh ro'yxat bergan bo'lishi mumkin.

  ✅ `is None` — aniq va to'g'ri.
""")

Natijaning muhim qismi:

text
=== 1. ⭐ Tuzoq ===
  def qosh(element, royxat=[]):

    qosh(1)  →  [1]
    qosh(2)  →  [1, 2]
    qosh(3)  →  [1, 2, 3]
    qosh(4)  →  [1, 2, 3, 4]

=== 2. Sabab: __defaults__ ===
    qosh(1) → [1]
      __defaults__ = ([1],)
      natija is __defaults__[0]: True

=== 5. Barcha o'zgaruvchan turlar ===
  Tur          1-chaqiruv         2-chaqiruv             3-chaqiruv
  ────────────────────────────────────────────────────────────────────────
  list         [1]                [1, 2]                 [1, 2, 3]
  dict         {1: 2}             {1: 2, 2: 4}           {1: 2, 2: 4, 3: 6}
  set          {1}                {1, 2}                 {1, 2, 3}

=== 7. ⚠️ is None vs not r ===
  Kirish       not r bilan              is None bilan
  ────────────────────────────────────────────────────────────
  None         ['sukut']                  ['sukut']
  []           ['sukut']              ⚠️ []
  0            ['sukut']              ⚠️ 0

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

Misol 2 — Sentinel va nozik holatlar

python
"""None ham yaroqli qiymat bo'lganda."""

from enum import Enum

print("=== 1. Muammo: None yaroqli qiymat ===")


def sozla_yomon(kalit, qiymat=None):
    """⚠️ None ni 'ko'rsatilmagan' deb qaraydi."""
    if qiymat is None:
        qiymat = "SUKUT"
    return {kalit: qiymat}


print(f"  def sozla(kalit, qiymat=None):\n")
print(f"    sozla('a')        → {sozla_yomon('a')}")
print(f"    sozla('a', 1)     → {sozla_yomon('a', 1)}")
print(f"    sozla('a', None)  → {sozla_yomon('a', None)}   "
      f"⚠️ None ni ataylab bermoqchi edik!")


print("\n=== 2. Sentinel yechimi ===")

YOQ = object()


def sozla_yaxshi(kalit, qiymat=YOQ):
    """✅ None ham yaroqli qiymat."""
    if qiymat is YOQ:
        qiymat = "SUKUT"
    return {kalit: qiymat}


print(f"  YOQ = object()")
print(f"  def sozla(kalit, qiymat=YOQ):\n")
print(f"    sozla('a')        → {sozla_yaxshi('a')}")
print(f"    sozla('a', 1)     → {sozla_yaxshi('a', 1)}")
print(f"    sozla('a', None)  → {sozla_yaxshi('a', None)}   ✅")


print("\n=== 3. Sentinel variantlari ===")

# 1. Oddiy object
YOQ1 = object()


# 2. repr bilan
class _Yoq:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

    def __repr__(self):
        return "<YOQ>"

    def __bool__(self):
        return False


YOQ2 = _Yoq()


# 3. Enum bilan (eng aniq)
class _Sentinel(Enum):
    YOQ = "yoq"

    def __repr__(self):
        return "<YOQ>"


YOQ3 = _Sentinel.YOQ


# 4. Maxsus sinf
class YOQTuri:
    __slots__ = ()

    def __repr__(self):
        return "YOQ"


YOQ4 = YOQTuri()

VARIANTLAR = [
    ("object()",            YOQ1),
    ("Singleton sinf",      YOQ2),
    ("Enum",                YOQ3),
    ("__slots__ sinf",      YOQ4),
]

print(f"  {'Variant':<20} {'repr':<20} {'bool':<8} {'Xotira'}")
print("  " + "─" * 58)
import sys
for nom, s in VARIANTLAR:
    print(f"  {nom:<20} {repr(s):<20} {str(bool(s)):<8} {sys.getsizeof(s)} B")

print("""
  ⭐ Tavsiya:
     • Modul ichida:  _YOQ = object()
     • Ochiq API da:  Enum yoki maxsus sinf (repr yaxshiroq)
     • Python 3.12+:  typing.Sentinel (PEP 661 — hali qabul qilinmagan)
""")


print("\n=== 4. Amaliy: xavfsiz dict.get ===")

YOQ = object()


def ol(d: dict, kalit, sukut=YOQ):
    """dict.get ga o'xshash, lekin None ni farqlaydi."""
    if kalit in d:
        return d[kalit]
    if sukut is YOQ:
        raise KeyError(kalit)
    return sukut


D = {"a": 1, "b": None, "yoq": 0}

SINOVLAR = [
    ("ol(d, 'a')",              lambda: ol(D, "a")),
    ("ol(d, 'b')",              lambda: ol(D, "b")),
    ("ol(d, 'z')",              lambda: ol(D, "z")),
    ("ol(d, 'z', None)",        lambda: ol(D, "z", None)),
    ("ol(d, 'z', 'sukut')",     lambda: ol(D, "z", "sukut")),
    ("d.get('b')",              lambda: D.get("b")),
    ("d.get('z')",              lambda: D.get("z")),
]

print(f"  d = {D}\n")
print(f"  {'Chaqiruv':<24} {'Natija'}")
print("  " + "─" * 48)
for kod, f in SINOVLAR:
    try:
        natija = repr(f())
    except KeyError as x:
        natija = f"❌ KeyError: {x}"
    print(f"  {kod:<24} {natija}")

print("""
  ⚠️ d.get('b') va d.get('z') ikkalasi ham None —
     kalit yo'qmi yoki qiymati None mi, farqlab bo'lmaydi.

  ⭐ Sentinel bilan farq aniq.
""")


print("\n=== 5. Bir-biriga bog'liq sukutlar ===")

print(f"  ❌ Boshqa parametrga tayanish mumkin emas:")
print(f"     def f(a, b=a): ...  →  NameError\n")


def olcham_yaxshi(kenglik=None, balandlik=None, nisbat=3):
    """✅ None + mantiq ichkarida."""
    if kenglik is None and balandlik is None:
        kenglik, balandlik = 80, 80 // nisbat
    elif kenglik is None:
        kenglik = balandlik * nisbat
    elif balandlik is None:
        balandlik = max(1, kenglik // nisbat)
    return kenglik, balandlik


SINOVLAR = [
    ({},                            "ikkalasi ham sukut"),
    ({"kenglik": 120},              "faqat kenglik"),
    ({"balandlik": 40},             "faqat balandlik"),
    ({"kenglik": 100, "balandlik": 50}, "ikkalasi"),
    ({"kenglik": 120, "nisbat": 4}, "nisbat bilan"),
]

print(f"  {'Argumentlar':<34} {'Natija':<14} Izoh")
print("  " + "─" * 66)
for kwargs, izoh in SINOVLAR:
    natija = olcham_yaxshi(**kwargs)
    print(f"  {str(kwargs):<34} {str(natija):<14} {izoh}")


print("\n=== 6. Sukut qiymatlarni tekshirish ===")

import inspect


def ozgaruvchan_sukutlarni_top(f):
    """O'zgaruvchan sukut qiymatlarni topadi."""
    OZGARUVCHAN = (list, dict, set, bytearray)
    natija = []
    try:
        sig = inspect.signature(f)
    except (ValueError, TypeError):
        return natija
    for nom, p in sig.parameters.items():
        if p.default is inspect.Parameter.empty:
            continue
        if isinstance(p.default, OZGARUVCHAN):
            natija.append((nom, type(p.default).__name__, p.default))
        elif isinstance(p.default, tuple):
            for i, el in enumerate(p.default):
                if isinstance(el, OZGARUVCHAN):
                    natija.append((f"{nom}[{i}]", type(el).__name__, el))
    return natija


def yomon1(a, r=[]): ...
def yomon2(a, d={}, s=set()): ...
def yomon3(a, t=(1, [])): ...
def yaxshi1(a, r=None): ...
def yaxshi2(a, t=(), f=frozenset()): ...
def yaxshi3(a=1, b="x", c=None): ...


FUNKSIYALAR = [yomon1, yomon2, yomon3, yaxshi1, yaxshi2, yaxshi3]

print(f"  {'Funksiya':<12} {'Muammolar'}")
print("  " + "─" * 56)
for f in FUNKSIYALAR:
    muammolar = ozgaruvchan_sukutlarni_top(f)
    if muammolar:
        matn = ", ".join(f"{n}={t}" for n, t, _ in muammolar)
        print(f"  {f.__name__:<12} ⚠️ {matn}")
    else:
        print(f"  {f.__name__:<12} ✅ toza")

print("""
  ⭐ Linterlar buni avtomatik topadi:
     ruff:            B006
     flake8-bugbear:  B006
     pylint:          W0102 (dangerous-default-value)
""")


print("\n=== 7. __defaults__ va __kwdefaults__ ===")


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


print(f"  def toliq(a, b, c=3, d=4, *args, e=5, f=6, **kwargs):\n")
print(f"    __defaults__     = {toliq.__defaults__}")
print(f"    __kwdefaults__   = {toliq.__kwdefaults__}")

print(f"\n  ⭐ __defaults__ OXIRIDAN bog'lanadi:")
print(f"     (3, 4) → c=3, d=4  (a va b sukutsiz)\n")

print(f"  inspect bilan to'liq:")
print(f"    {'Parametr':<10} {'Sukut':<12} {'Tur'}")
print("    " + "─" * 48)
for nom, p in inspect.signature(toliq).parameters.items():
    sukut = "—" if p.default is inspect.Parameter.empty else repr(p.default)
    print(f"    {nom:<10} {sukut:<12} {p.kind.name}")

print(f"\n  ⚠️ Sukutni ish vaqtida o'zgartirish:")


def g(x=1):
    return x


print(f"    g() = {g()}")
g.__defaults__ = (99,)
print(f"    g.__defaults__ = (99,)")
print(f"    g() = {g()}   ⚠️ ishlaydi, lekin QILMANG")

Natijaning muhim qismi:

text
=== 2. Sentinel yechimi ===
    sozla('a')        → {'a': 'SUKUT'}
    sozla('a', 1)     → {'a': 1}
    sozla('a', None)  → {'a': None}   ✅

=== 4. Amaliy: xavfsiz dict.get ===
  Chaqiruv                 Natija
  ────────────────────────────────────────────────
  ol(d, 'a')               1
  ol(d, 'b')               None
  ol(d, 'z')               ❌ KeyError: 'z'
  ol(d, 'z', None)         None
  d.get('b')               None
  d.get('z')               None

=== 6. Sukut qiymatlarni tekshirish ===
  Funksiya     Muammolar
  ────────────────────────────────────────────────────────
  yomon1       ⚠️ r=list
  yomon2       ⚠️ d=dict, s=set
  yomon3       ⚠️ t[1]=list
  yaxshi1      ✅ toza

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

Misol 3 — Qachon o'zgaruvchan sukut foydali

python
"""Tuzoq — ba'zan xususiyat."""

import time
from functools import lru_cache

print("=== 1. Kesh (memoizatsiya) ===")


def fib_kesh(n, kesh={0: 0, 1: 1}):
    """⚠️ O'zgaruvchan sukut — ATAYLAB kesh sifatida."""
    if n not in kesh:
        kesh[n] = fib_kesh(n - 1, kesh) + fib_kesh(n - 2, kesh)
    return kesh[n]


def fib_sekin(n):
    """Keshsiz — eksponensial."""
    return n if n < 2 else fib_sekin(n - 1) + fib_sekin(n - 2)


@lru_cache(maxsize=None)
def fib_lru(n):
    """✅ Standart usul."""
    return n if n < 2 else fib_lru(n - 1) + fib_lru(n - 2)


N = 30

boshlandi = time.perf_counter()
n1 = fib_sekin(N)
vaqt_sekin = time.perf_counter() - boshlandi

boshlandi = time.perf_counter()
n2 = fib_kesh(N)
vaqt_kesh = time.perf_counter() - boshlandi

boshlandi = time.perf_counter()
n3 = fib_lru(N)
vaqt_lru = time.perf_counter() - boshlandi

assert n1 == n2 == n3

print(f"  fib({N}) = {n1:,}\n")
print(f"  {'Usul':<26} {'Vaqt':>12}")
print("  " + "─" * 40)
print(f"  {'Keshsiz (rekursiv)':<26} {vaqt_sekin * 1000:>9.2f} ms")
print(f"  {'O`zgaruvchan sukut':<26} {vaqt_kesh * 1000:>9.4f} ms")
print(f"  {'@lru_cache':<26} {vaqt_lru * 1000:>9.4f} ms")

print(f"\n  Kesh holati:")
print(f"    fib_kesh.__defaults__[0] — {len(fib_kesh.__defaults__[0])} yozuv")
print(f"    fib_lru.cache_info() — {fib_lru.cache_info()}")

print("""
  ⚠️ Ikkalasi ham ishlaydi, LEKIN:
     • O'zgaruvchan sukut — niyat yashirin, kesh tozalanmaydi
     • @lru_cache — aniq, maxsize bor, cache_clear() bor
""")

print(f"  @lru_cache imkoniyatlari:")
print(f"    fib_lru.cache_clear()   — tozalash")
print(f"    fib_lru.cache_info()    — statistika")
print(f"    maxsize=128             — chegara (LRU)")


print("\n=== 2. Chaqiruvlarni sanash ===")


def sana_sukut(hisob=[0]):
    """⚠️ Ro'yxat ichida hisoblagich."""
    hisob[0] += 1
    return hisob[0]


def sana_atribut():
    """✅ Funksiya atributi — aniqroq."""
    sana_atribut.hisob += 1
    return sana_atribut.hisob


sana_atribut.hisob = 0


class Sanagich:
    """✅ Sinf — eng aniq."""

    def __init__(self):
        self.hisob = 0

    def __call__(self):
        self.hisob += 1
        return self.hisob


sana_sinf = Sanagich()

USULLAR = [
    ("Sukut ro'yxat",   sana_sukut),
    ("Funksiya atributi", sana_atribut),
    ("Sinf (__call__)", sana_sinf),
]

print(f"  {'Usul':<22} {'1':>4} {'2':>4} {'3':>4}  Holatga kirish")
print("  " + "─" * 60)
for nom, f in USULLAR:
    natijalar = [f() for _ in range(3)]
    if nom == "Sukut ro'yxat":
        kirish = "f.__defaults__[0][0]"
    elif nom == "Funksiya atributi":
        kirish = "f.hisob"
    else:
        kirish = "f.hisob"
    print(f"  {nom:<22} {natijalar[0]:>4} {natijalar[1]:>4} "
          f"{natijalar[2]:>4}  {kirish}")

print("""
  ⭐ Ikkalasi ishlaydi, lekin funksiya atributi va sinf
     NIYATNI ochiq ko'rsatadi.
""")


print("\n=== 3. Oldindan hisoblash ===")


def tozala_sukut(matn, jadval=str.maketrans("", "", ".,!?;:")):
    """⚠️ Jadval bir marta yaratiladi (sukut sifatida)."""
    return matn.translate(jadval)


JADVAL = str.maketrans("", "", ".,!?;:")


def tozala_konstanta(matn):
    """✅ Modul konstantasi — aniqroq."""
    return matn.translate(JADVAL)


def tozala_ichkarida(matn):
    """❌ Har chaqiruvda yangi jadval."""
    return matn.translate(str.maketrans("", "", ".,!?;:"))


MATN = "Salom, dunyo! Qalaysiz?" * 10

import timeit
SOZLASH = "from __main__ import tozala_sukut, tozala_konstanta, tozala_ichkarida, MATN"

print(f"  {'Usul':<26} {'Vaqt':>12}")
print("  " + "─" * 42)
for nom, kod in [
    ("Sukut argument", "tozala_sukut(MATN)"),
    ("Modul konstantasi", "tozala_konstanta(MATN)"),
    ("Har chaqiruvda", "tozala_ichkarida(MATN)"),
]:
    vaqt = timeit.timeit(kod, setup=SOZLASH, number=50_000)
    print(f"  {nom:<26} {vaqt:>9.3f} s")

print("""
  ⭐ Sukut va konstanta bir xil tez.
     Konstanta — o'qilishi yaxshiroq va tasodifan
     o'zgartirib bo'lmaydi (sukut argumentni o'zgartirish mumkin).
""")


print("\n=== 4. Lokal nom optimallashtirishi ===")


def yigindi_oddiy(r):
    natija = 0
    for x in r:
        natija += len(str(x))
    return natija


def yigindi_lokal(r, _len=len, _str=str):
    """⚠️ Eski mikro-optimallashtirish hiylasi."""
    natija = 0
    for x in r:
        natija += _len(_str(x))
    return natija


R = list(range(10_000))
SOZLASH = "from __main__ import yigindi_oddiy, yigindi_lokal, R"

print(f"  {'Usul':<26} {'Vaqt':>12}")
print("  " + "─" * 42)
for nom, kod in [("Oddiy", "yigindi_oddiy(R)"),
                 ("Lokal sukut bilan", "yigindi_lokal(R)")]:
    vaqt = timeit.timeit(kod, setup=SOZLASH, number=200)
    print(f"  {nom:<26} {vaqt:>9.3f} s")

print("""
  ⚠️ Zamonaviy CPython da farq juda kichik (~2-5%).
     Kod o'qilishi esa sezilarli yomonlashadi.

  ⭐ Bu hiylani ISHLATMANG — faqat isbotlangan tor joyda.
""")


print("\n=== 5. Xulosa: qachon ataylab ===")

print("""
  ┌──────────────────────────┬───────────────────────────────────┐
  │ Maqsad                   │ To'g'ri usul                      │
  ├──────────────────────────┼───────────────────────────────────┤
  │ Kesh                     │ @lru_cache / @cache ⭐             │
  │ Chaqiruvlarni sanash     │ Funksiya atributi yoki sinf ⭐     │
  │ Oldindan hisoblash       │ Modul konstantasi ⭐               │
  │ Holat saqlash            │ Sinf ⭐                            │
  │ Lokal nom (tezlik)       │ Deyarli hech qachon kerak emas    │
  │ Yangi bo'sh konteyner    │ =None + ichkarida yaratish ⭐      │
  └──────────────────────────┴───────────────────────────────────┘

  ⭐ Har holat uchun aniqroq muqobil bor.
     O'zgaruvchan sukut qiymat — niyatni YASHIRADI.
""")


print("\n=== 6. Kesh tozalash muammosi ===")

print(f"  O'zgaruvchan sukut bilan:")
print(f"    fib_kesh kesh hajmi: {len(fib_kesh.__defaults__[0])}")
print(f"    Tozalash: fib_kesh.__defaults__[0].clear()  ⚠️ hiyla")
fib_kesh.__defaults__[0].clear()
fib_kesh.__defaults__[0].update({0: 0, 1: 1})
print(f"    Tozalangandan keyin: {len(fib_kesh.__defaults__[0])}")

print(f"\n  @lru_cache bilan:")
print(f"    Kesh: {fib_lru.cache_info()}")
fib_lru.cache_clear()
print(f"    fib_lru.cache_clear()")
print(f"    Kesh: {fib_lru.cache_info()}   ✅ toza API")

print(f"\n  Chegara bilan:")


@lru_cache(maxsize=3)
def kichik_kesh(n):
    return n * 2


for i in range(6):
    kichik_kesh(i)
print(f"    @lru_cache(maxsize=3), 6 ta chaqiruv:")
print(f"    {kichik_kesh.cache_info()}")
print(f"    ⭐ Eng kam ishlatilganlar chiqarildi (LRU)")

Natijaning muhim qismi:

text
=== 1. Kesh (memoizatsiya) ===
  fib(30) = 832,040

  Usul                               Vaqt
  ────────────────────────────────────────
  Keshsiz (rekursiv)            284.12 ms
  O`zgaruvchan sukut              0.0412 ms
  @lru_cache                      0.0284 ms

=== 2. Chaqiruvlarni sanash ===
  Usul                      1    2    3  Holatga kirish
  ────────────────────────────────────────────────────────────
  Sukut ro'yxat             1    2    3  f.__defaults__[0][0]
  Funksiya atributi         1    2    3  f.hisob
  Sinf (__call__)           1    2    3  f.hisob

=== 6. Kesh tozalash muammosi ===
  @lru_cache bilan:
    Kesh: CacheInfo(hits=28, misses=31, maxsize=None, currsize=31)
    fib_lru.cache_clear()
    Kesh: CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)   ✅ toza API

Nima ko'rsatdi: 2.5-bo'lim.

Misol 4 — Amaliy: konfiguratsiya funksiyalari

python
"""Sukut qiymatlar bilan to'g'ri API dizayni."""

from dataclasses import dataclass, field, replace
from datetime import datetime, timedelta
from enum import Enum
from typing import Any

print("=== Hisobot generatori ===\n")

_YOQ = object()


class Format(Enum):
    MATN = "matn"
    CSV = "csv"
    JSON = "json"


@dataclass(frozen=True)
class Sozlamalar:
    """O'zgarmas sozlamalar — sukut qiymat sifatida xavfsiz."""
    kenglik: int = 60
    ajratgich: str = "│"
    ramka: bool = True
    raqamlar: bool = False
    format: Format = Format.MATN

    def __post_init__(self):
        if not 20 <= self.kenglik <= 200:
            raise ValueError(f"kenglik 20-200 oralig'ida: {self.kenglik}")


SUKUT_SOZLAMALAR = Sozlamalar()             # ⭐ o'zgarmas — sukut sifatida xavfsiz


def hisobot(
    yozuvlar: list[dict],
    sarlavha: str = "HISOBOT",
    *,
    maydonlar: tuple[str, ...] = (),        # ⭐ tuple, list emas
    filtrlar: dict | None = None,           # ⭐ None naqshi
    sozlamalar: Sozlamalar = SUKUT_SOZLAMALAR,  # ⭐ o'zgarmas obyekt
    vaqt: datetime | None = None,           # ⭐ None — har chaqiruvda yangi
    chegara: int | Any = _YOQ,              # ⭐ sentinel — None ham yaroqli
) -> str:
    """Yozuvlardan hisobot yaratadi.

    Argumentlar:
        yozuvlar: Ma'lumot yozuvlari
        sarlavha: Hisobot sarlavhasi
        maydonlar: Ko'rsatiladigan maydonlar (bo'sh — hammasi)
        filtrlar: {maydon: qiymat} filtrlari
        sozlamalar: Ko'rinish sozlamalari
        vaqt: Hisobot vaqti (None — hozirgi vaqt)
        chegara: Maksimal qatorlar (None — cheklovsiz, berilmasa — 10)
    """
    # Sukutlarni hal qilish
    filtrlar = filtrlar or {}
    vaqt = vaqt if vaqt is not None else datetime.now()
    if chegara is _YOQ:
        chegara = 10
    if not maydonlar and yozuvlar:
        maydonlar = tuple(yozuvlar[0])

    # Filtrlash
    toza = [
        y for y in yozuvlar
        if all(y.get(k) == v for k, v in filtrlar.items())
    ]
    if chegara is not None:
        toza = toza[:chegara]

    # Chiqarish
    s = sozlamalar
    if s.format is Format.CSV:
        qatorlar = [",".join(maydonlar)]
        qatorlar += [",".join(str(y.get(m, "")) for m in maydonlar) for y in toza]
        return "\n".join(qatorlar)

    if s.format is Format.JSON:
        import json
        return json.dumps(
            {"sarlavha": sarlavha, "vaqt": vaqt.isoformat(), "yozuvlar": toza},
            ensure_ascii=False, indent=2,
        )

    # MATN
    kengliklar = {
        m: max(len(str(m)), max((len(str(y.get(m, ""))) for y in toza), default=0))
        for m in maydonlar
    }
    qatorlar = []
    if s.ramka:
        qatorlar.append(f"┌─ {sarlavha}  ({vaqt:%Y-%m-%d %H:%M})")
        qatorlar.append("│")

    prefiks = "│  " if s.ramka else "  "
    sarlavha_qatori = f"  {s.ajratgich} ".join(
        f"{m:<{kengliklar[m]}}" for m in maydonlar
    )
    if s.raqamlar:
        sarlavha_qatori = f"{'#':>3}  {sarlavha_qatori}"
    qatorlar.append(prefiks + sarlavha_qatori)
    qatorlar.append(prefiks + "─" * len(sarlavha_qatori))

    for i, y in enumerate(toza, 1):
        qator = f"  {s.ajratgich} ".join(
            f"{str(y.get(m, '')):<{kengliklar[m]}}" for m in maydonlar
        )
        if s.raqamlar:
            qator = f"{i:>3}  {qator}"
        qatorlar.append(prefiks + qator)

    if s.ramka:
        qatorlar.append("│")
        qatorlar.append(f"└─ {len(toza)} yozuv")

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


# ═══ NAMOYISH ═══

YOZUVLAR = [
    {"id": 1, "ism": "Aziz", "bolim": "IT", "maosh": 7_000_000},
    {"id": 2, "ism": "Bobur", "bolim": "HR", "maosh": 5_000_000},
    {"id": 3, "ism": "Aziza", "bolim": "IT", "maosh": 8_000_000},
    {"id": 4, "ism": "Dilnoza", "bolim": "Moliya", "maosh": 6_000_000},
    {"id": 5, "ism": "Eldor", "bolim": "IT", "maosh": 9_000_000},
]

print("=== 1. Sukut qiymatlar bilan ===\n")
print(hisobot(YOZUVLAR))


print("\n\n=== 2. Maydonlarni tanlash ===\n")
print(hisobot(YOZUVLAR, "ISM VA MAOSH", maydonlar=("ism", "maosh")))


print("\n\n=== 3. Filtr bilan ===\n")
print(hisobot(YOZUVLAR, "IT BO'LIMI", filtrlar={"bolim": "IT"}))


print("\n\n=== 4. Sozlamalar bilan ===\n")
s = Sozlamalar(raqamlar=True, ajratgich="┃")
print(hisobot(YOZUVLAR, "RAQAMLANGAN", sozlamalar=s, chegara=3))


print("\n\n=== 5. ⭐ Sentinel: chegara ===\n")

VARIANTLAR = [
    ("chegara berilmadi",       {}),
    ("chegara=2",               {"chegara": 2}),
    ("chegara=None",            {"chegara": None}),
]

for nom, kwargs in VARIANTLAR:
    natija = hisobot(YOZUVLAR, format if False else "SINOV", **kwargs)
    qatorlar_soni = natija.count("\n")
    oxirgi = natija.strip().splitlines()[-1].strip()
    print(f"  {nom:<24} → {oxirgi}")

print("""
  ⭐ chegara=None — "cheklov yo'q" (5 yozuv)
     chegara berilmadi — sukut 10 (5 yozuv, chunki jami 5)
     chegara=2 — 2 yozuv

     None ham YAROQLI qiymat, shuning uchun sentinel kerak.
""")


print("\n=== 6. Boshqa formatlar ===\n")

print(f"  CSV:")
csv_s = Sozlamalar(format=Format.CSV)
for q in hisobot(YOZUVLAR, sozlamalar=csv_s, chegara=3,
                 maydonlar=("ism", "bolim", "maosh")).splitlines():
    print(f"    {q}")

print(f"\n  JSON:")
json_s = Sozlamalar(format=Format.JSON)
natija = hisobot(YOZUVLAR, "TEST", sozlamalar=json_s, chegara=2,
                 vaqt=datetime(2026, 9, 8, 12, 0))
for q in natija.splitlines()[:10]:
    print(f"    {q}")
print(f"    ...")


print("\n\n=== 7. Sukut qiymatlar tahlili ===\n")

import inspect

sig = inspect.signature(hisobot)

print(f"  {'Parametr':<14} {'Sukut':<28} {'Xavfsizmi'}")
print("  " + "─" * 62)

OZGARUVCHAN = (list, dict, set, bytearray)

for nom, p in sig.parameters.items():
    if p.default is inspect.Parameter.empty:
        sukut, belgi = "(majburiy)", "  "
    else:
        sukut = repr(p.default)
        if len(sukut) > 26:
            sukut = sukut[:24] + "…"
        belgi = "⚠️" if isinstance(p.default, OZGARUVCHAN) else "✅"
    print(f"  {nom:<14} {sukut:<28} {belgi}")

print("""
  ⭐ Ishlatilgan naqshlar:

     sarlavha = "HISOBOT"           o'zgarmas satr
     maydonlar = ()                 o'zgarmas tuple (list emas)
     filtrlar = None                None naqshi
     sozlamalar = SUKUT_SOZLAMALAR  frozen dataclass — xavfsiz
     vaqt = None                    har chaqiruvda yangi vaqt
     chegara = _YOQ                 sentinel (None ham yaroqli)
""")


print("\n=== 8. Sozlamalarni o'zgartirish ===\n")

asosiy = Sozlamalar()
kengaytirilgan = replace(asosiy, kenglik=120, raqamlar=True)
csv_variant = replace(asosiy, format=Format.CSV)

print(f"  asosiy         = {asosiy}")
print(f"  kengaytirilgan = {kengaytirilgan}")
print(f"  csv_variant    = {csv_variant}")

print(f"\n  ⭐ frozen dataclass:")
print(f"     • Sukut qiymat sifatida xavfsiz (o'zgartirib bo'lmaydi)")
print(f"     • replace() bilan variantlar yaratiladi")
print(f"     • __post_init__ da validatsiya")

try:
    asosiy.kenglik = 100
except Exception as x:
    print(f"\n     asosiy.kenglik = 100 → ❌ {type(x).__name__}")

try:
    Sozlamalar(kenglik=5)
except ValueError as x:
    print(f"     Sozlamalar(kenglik=5) → ❌ ValueError: {x}")

Natijaning muhim qismi:

text
=== 1. Sukut qiymatlar bilan ===

  ┌─ HISOBOT  (2026-09-14 13:34)
  │
  │  id  │ ism      │ bolim   │ maosh
  │  ────────────────────────────────────
  │  1   │ Aziz     │ IT      │ 7000000
  │  2   │ Bobur    │ HR      │ 5000000
  │
  └─ 5 yozuv

=== 7. Sukut qiymatlar tahlili ===

  Parametr       Sukut                        Xavfsizmi
  ──────────────────────────────────────────────────────────────
  yozuvlar       (majburiy)
  sarlavha       'HISOBOT'                    ✅
  maydonlar      ()                           ✅
  filtrlar       None                         ✅
  sozlamalar     Sozlamalar(kenglik=60, a…    ✅
  vaqt           None                         ✅
  chegara        <object object at 0x0000…    ✅

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
"Sukut qiymat har chaqiruvda yaratiladi" def paytida bir marta
"def f(r=[]) har safar yangi ro'yxat" Bitta ro'yxat qayta ishlatiladi
"Faqat list bilan muammo" dict, set, bytearray, obyektlar ham
"if not r: r = [] yetarli" Bo'sh ro'yxatni ham almashtiradi. is None
"tuple sukut har doim xavfsiz" (1, []) — ichida o'zgaruvchan
"vaqt=datetime.now() ishlaydi" Vaqt def paytida qotib qoladi
"O'zgaruvchan sukut — har doim xato" Ataylab kesh sifatida ishlatiladi (lekin muqobil yaxshiroq)
"def f(a=1, b) mumkin" SyntaxError
"def f(a, b=a) ishlaydi" NameError

6. Keng tarqalgan xatolar va yechimlari

1. O'zgaruvchan sukut

python
def f(r=[]):                        # ❌
def f(r=None):                      # ✅
    r = [] if r is None else r

2. not r tekshiruvi

python
def f(r=None):
    if not r: r = []                # ⚠️ [] ni ham almashtiradi
    if r is None: r = []            # ✅

3. Vaqt/tasodifiy sukut

python
def f(t=datetime.now()): ...        # ⚠️ qotib qoladi
def f(t=random.random()): ...       # ⚠️ bir xil qiymat

def f(t=None):                      # ✅
    t = t or datetime.now()

4. None ham yaroqli qiymat

python
def f(x=None):                      # ⚠️ None ni farqlab bo'lmaydi
_YOQ = object()
def f(x=_YOQ):                      # ✅

5. Sukutsiz parametr sukutlidan keyin

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

6. Tuple ichida o'zgaruvchan

python
def f(t=(1, [])): ...               # ⚠️
def f(t=(1, ())): ...               # ✅

7. Sukut qiymat boshqa parametrga tayanishi

python
def f(a, b=a): ...                  # ❌ NameError
def f(a, b=None):                   # ✅
    b = a if b is None else b

8. Xavfli sukut

python
def ochish(yol, rejim="w"): ...     # ⚠️ tasodifan o'chirish
def ochish(yol, rejim="r"): ...     # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 7.2-dars (o'tilgan): argument uzatish, o'zgaruvchanlik
  • 7.4-dars: nomli argumentlar
  • 7.6-dars: faqat nomli argumentlar (*)
  • 6.18-dars (o'tilgan): nusxa olish
  • 6.5, 6.9-darslar (o'tilgan): tuple, frozenset — xavfsiz sukutlar
  • 8-qism: dataclass(frozen=True), field(default_factory=...)
  • 10-qism: functools.lru_cache, partial
  • Linterlar: ruff B006, pylint W0102

8. Eng yaxshi amaliyotlar

  1. O'zgaruvchan sukut — hech qachon. =None + ichkarida yaratish.

  2. is None, not r emas. Bo'sh ro'yxat — yaroqli qiymat.

  3. None ham yaroqli bo'lsa — sentinel. _YOQ = object().

  4. Vaqt, tasodif, ID — doim None. def paytida hisoblanmaslik uchun.

  5. O'zgarmas sukut qiymatlar: (), frozenset(), "", 0, None, frozen dataclass.

  6. Sukut — eng ko'p ishlatiladigan va xavfsiz holat. rejim="r", "w" emas.

  7. Linter ishlating. ruff B006 buni avtomatik topadi.

  8. Kesh uchun @lru_cache. O'zgaruvchan sukut niyatni yashiradi.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
def f1(x, r=[]): r.append(x); return r
def f2(x, r=None): r = r or []; r.append(x); return r
def f3(x, d={}): d[x] = 1; return d
def f4(x, t=()): return t + (x,)
def f5(x, s="") : return s + str(x)

1.  print(f1(1), f1(2), f1(3))
2.  print(f2(1), f2(2), f2(3))
3.  print(f3(1), f3(2))
4.  print(f4(1), f4(2))
5.  print(f5(1), f5(2))
6.  def g(x=[]): return len(x)
    g().__class__; g([1,2]); print(g())
7.  def h(a=1, b=2): return a, b
    print(h.__defaults__)
8.  def k(a, *, b=1, c=2): pass
    print(k.__defaults__, k.__kwdefaults__)
9.  import time
    def m(t=time.time()): return t
    a = m(); time.sleep(0.01); print(a == m())
10. def n(r=[]): r = r + [1]; return r
    print(n(), n())
11. def p(t=(1, [])): t[1].append(1); return t
    print(p(), p())
12. def q(x=None): return x is None
    print(q(), q(None), q(0))
Javoblar
  1. [1, 2, 3] [1, 2, 3] [1, 2, 3] — tuzoq ikki qavat: uchala chaqiruv bitta ro'yxatni qaytaradi, print esa uni hammasi bajarilgandan keyin chiqaradi
  2. [1] [2] [3] —
  3. {1: 1, 2: 1} {1: 1, 2: 1} — ikkalasi ham bitta lug'at, print oxirgi holatini ko'rsatadi
  4. (1,) (2,) — tuple o'zgarmas
  5. 1 2 — str o'zgarmas
  6. 0 — g([1,2]) sukutni o'zgartirmaydi
  7. (1, 2)
  8. None {'b': 1, 'c': 2}
  9. True — vaqt def paytida qotib qolgan
  10. [1] [1] — r = r + [1] yangi ro'yxat
  11. (1, [1, 1]) (1, [1, 1]) — tuple o'zgarmas, lekin ichidagi list umumiy; ikkala chaqiruv bitta tuple'ni qaytaradi
  12. True True False

Vazifa 2: Xatolarni tuzating

python
1.  def f(x, r=[]): r.append(x); return r
2.  def f(x, d={}): d[x] = 1; return d
3.  def f(t=datetime.now()): return t
4.  def f(r=None):
        if not r: r = [0]
        return r
5.  def f(a=1, b): return a, b
6.  def f(a, b=a): return a, b
7.  def f(x=None): ...   # None ham yaroqli qiymat
8.  def ochish(yol, rejim="w"): ...
Javoblar
python
1.  def f(x, r=None): r = [] if r is None else r; r.append(x); return r
2.  def f(x, d=None): d = {} if d is None else d; d[x] = 1; return d
3.  def f(t=None): t = t or datetime.now(); return t
4.  if r is None: r = [0]
5.  def f(a, b=1): return a, b    # yoki def f(*, a=1, b)
6.  def f(a, b=None): b = a if b is None else b; return a, b
7.  _YOQ = object(); def f(x=_YOQ): ...
8.  def ochish(yol, rejim="r"): ...

Vazifa 3: Xavfsiz sukutlar kutubxonasi

Funksiyalar yozing (barchasi xavfsiz sukut bilan):

  1. qosh(x, r=None) — ro'yxatga qo'shish
  2. guruhla(elementlar, kalit_f, natija=None) — guruhlash
  3. birlashtir(d1, d2=None, chuqur=False) — lug'atlarni birlashtirish
  4. yozuv(matn, vaqt=None, daraja="INFO") — log yozuvi
  5. sozla(kalit, qiymat=SENTINEL) — None ham yaroqli
  6. Har biri uchun test: ketma-ket chaqiruvlar mustaqilligini tekshiring

Vazifa 4: Sukut tekshiruvchi

Vosita yozing:

  1. Modul funksiyalarini skanerlaydi (inspect)
  2. O'zgaruvchan sukutlarni topadi (ichma-ich ham)
  3. datetime.now(), random() kabi "vaqt bog'liq" sukutlarni topadi
  4. Tuzatish taklifini beradi
  5. ruff/pylint natijasi bilan solishtiradi
  6. Dekorator versiyasi: @sukutlarni_tekshir

Vazifa 5: Sentinel kutubxonasi

  1. Sentinel(nom) — nomli sentinel yaratuvchi
  2. repr, bool, copy/deepcopy to'g'ri ishlasin
  3. pickle bilan ishlasin (singleton saqlanishi)
  4. Tur ko'rsatkichlari bilan (TypeAlias)
  5. is_sentinel(x) yordamchisi
  6. PEP 661 taklifi bilan solishtiring

Vazifa 6: Konfiguratsiya API

Funksiya yozing (10+ sozlama bilan):

  1. Majburiy va ixtiyoriy parametrlarni ajrating
  2. * bilan nomli argumentlarni majburiy qiling
  3. frozen dataclass sozlamalar obyekti
  4. None va sentinel farqini ko'rsating
  5. Validatsiya __post_init__ da
  6. replace() bilan variantlar

Vazifa 7: O'ylash

Nega Python sukut qiymatni def paytida hisoblaydi, chaqiruv paytida emas? Bu xato emasmi?

Javob

Bu — ataylab qilingan dizayn qarori, xato emas. Lekin bahsli.

Dalillar "def paytida" foydasiga:

1. Izchillik: def — oddiy ifoda.

Pythonda def — bajariladigan buyruq, e'lon emas:

python
def f(x=hisobla()):
    ...

def bajarilganda:

  1. Funksiya obyekti yaratiladi
  2. Sukut qiymatlar hisoblanadi (oddiy ifoda kabi)
  3. Nom bog'lanadi

Bu — boshqa hamma joydagi qoida bilan bir xil:

python
x = hisobla()               # hozir hisoblanadi
d = {"a": hisobla()}        # hozir
def f(x=hisobla()): ...     # hozir — IZCHIL

Agar sukut qiymat kechiktirilsa, def maxsus qoidaga ega bo'lardi.

2. Tezlik.

Chaqiruv paytida hisoblansa, har chaqiruvda ish bajarilardi:

python
def f(x=[]):                # har chaqiruvda yangi ro'yxat
def f(x=KATTA_KONSTANTA):   # har chaqiruvda qidiruv
def f(x=hisobla()):         # har chaqiruvda hisoblash

Funksiya chaqiruvi — Pythonda eng ko'p bajariladigan amal. Uni sekinlashtirish jiddiy narx.

3. Yopilma semantikasi bilan mos.

python
def yaratuvchi(n):
    def ichki(x=n):         # n — yaratilish paytidagi qiymat
        return x
    return ichki

f1 = yaratuvchi(1)
f2 = yaratuvchi(2)
f1(), f2()                  # 1, 2 — har biri o'z qiymatini eslab qoldi

Bu — foydali xatti-harakat. Kechiktirilsa, n sikl o'zgaruvchisi bo'lganda kech bog'lanish muammosi chiqardi (6.15-dars).

4. Ba'zan ataylab kerak.

python
def f(_kesh={}):            # kesh
def f(_hisob=[0]):          # hisoblagich
def f(_len=len):            # lokal nom

Dalillar "chaqiruv paytida" foydasiga:

1. Tuzoq — eng ko'p uchraydigan Python xatosi.

Har bir yangi Pythonchi bunga tushadi. StackOverflow'da minglab savol.

2. Intuitiv kutish boshqacha.

python
def f(r=[]):

Ko'pchilik "har chaqiruvda yangi bo'sh ro'yxat" deb o'qiydi. Bu — tabiiy o'qish.

3. Boshqa tillar boshqacha:

  • Ruby: def f(r = []) — har chaqiruvda yangi
  • JavaScript: function f(r = []) — har chaqiruvda yangi
  • C++: void f(vector<int> r = {}) — har chaqiruvda yangi

Python bu masalada yolg'iz.

Nega o'zgartirilmaydi:

1. Orqaga moslik.

Millionlab kod qatori mavjud xatti-harakatga tayanadi (kesh, hisoblagich, lokal nom hiylasi).

2. Muqobil sintaksis taklif qilingan:

python
def f(r=>[]):               # PEP 671 — "late-bound defaults"
def f(r:=[]):

PEP 671 (2021, Chris Angelico) aynan shuni taklif qildi:

python
def f(r=>[]):
    # r har chaqiruvda yangi []

Holat: draft. Muhokama davom etmoqda. Qarshi dalillar:

  • Yangi sintaksis — o'rganish narxi
  • =None naqshi ishlaydi va tanish
  • Ikki xil sukut — chalkashlik

3. Linterlar muammoni hal qiladi.

ruff B006, pylint W0102, flake8-bugbear B006

Har qanday zamonaviy loyihada bu xato avtomatik topiladi.

Xulosa:

Bu — klassik trade-off:

"def paytida" (Python) "chaqiruv paytida"
Izchillik maxsus qoida
Tezlik har chaqiruvda
Intuitivlik
Yopilma tabiiy murakkabroq
Kesh naqshi mumkin

Python izchillik va tezlikni intuitivlikdan ustun qo'ydi. Bu — Pythonning umumiy falsafasiga (def oddiy ifoda) mos, lekin yangi boshlovchilar uchun tuzoq.

Amaliy javob: =None naqshini o'rganing va linter ishlating. Bu — muammoni to'liq hal qiladi.

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


Xulosa

Bu darsda sukut qiymatlarni va Pythonning eng mashhur tuzog'ini o'rgandik.

Eng muhim uch fikr:

  1. Sukut qiymat def paytida bir marta hisoblanadi. U funksiya obyektida (__defaults__) saqlanadi va har chaqiruvda o'sha obyekt ishlatiladi. Shuning uchun def f(r=[]) da barcha chaqiruvlar bitta ro'yxatni bo'lishadi.

  2. =None naqshi — standart yechim. if r is None: r = [] — va aynan is None, not r emas: bo'sh ro'yxat foydalanuvchi bergan yaroqli qiymat bo'lishi mumkin. None ham yaroqli bo'lsa — sentinel (_YOQ = object()).

  3. Vaqt, tasodif, o'zgaruvchan konteyner — hech qachon sukut sifatida. datetime.now() def paytida qotib qoladi. Xavfsiz sukutlar: None, (), frozenset(), "", sonlar, frozen dataclass.

Keyingi darsda nomli argumentlarni batafsil ko'ramiz: qachon ishlatish, o'qilishga ta'siri va API dizaynidagi roli.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
7.3-dars: Standart qiymatlar va mashhur tuzoq — IlmHamroh