IlmHamroh
Python kursi/OOP16/20-dars41 daqiqa
Mundarija (21)

8.16-dars: @staticmethod va @classmethod

8-QISM — OBYEKTGA YO'NALTIRILGAN DASTURLASH · 16-dars


1. Kirish va motivatsiya

Bu ikki metod deyarli bir xil ko'rinadi:

python
class Sana:
    @staticmethod
    def bugun_static():
        return Sana(15, 3, 2026)        # ⚠️ sinf nomi qattiq yozilgan

    @classmethod
    def bugun_class(cls):
        return cls(15, 3, 2026)         # ⭐ haqiqiy sinf

Farq avlod sinfda ko'rinadi:

python
class UzbekSana(Sana):
    pass

type(UzbekSana.bugun_static())          # Sana        ⚠️
type(UzbekSana.bugun_class())           # UzbekSana   ✅

Va bu chalkash:

python
class A:
    @staticmethod
    def f(): return "static"

    @classmethod
    def g(cls): return f"class: {cls.__name__}"

A.f()                                   # 'static'
A().f()                                 # 'static'
A.g()                                   # 'class: A'
A().g()                                 # 'class: A'      ⭐ nusxa emas
type(A.__dict__["f"])                   # <class 'staticmethod'>
type(A.f)                               # <class 'function'>    ⭐ farqli!

Bu darsda:

  • cls va self — nima farqi
  • Fabrika metodlari — asosiy qo'llanish
  • Meros va cls() ning ahamiyati
  • @staticmethod — qachon haqiqatan kerak
  • Ikkalasi ham deskriptor ekani
  • classmethod bilan sinf holatini boshqarish

2. Nazariya — chuqur tushuntirish

2.1. Uch metod turi

python
class A:
    def nusxa(self): ...                # self — NUSXA
    @classmethod
    def sinf(cls): ...                  # cls — SINF
    @staticmethod
    def statik(): ...                   # hech narsa
Birinchi param A.f() A().f() Meros
Nusxa metod self TypeError self — avlod nusxasi
@classmethod cls cls — avlod sinf
@staticmethod — —

cls — chaqirilgan sinf, aniqlangan sinf emas:

python
class Ota:
    @classmethod
    def kim(cls): return cls.__name__

class Bola(Ota): pass

Ota.kim()                       # 'Ota'
Bola.kim()                      # 'Bola'   ⭐
Bola().kim()                    # 'Bola'   ⭐ nusxadan ham

2.2. Fabrika metodlari — asosiy qo'llanish

__init__ — bitta yo'l. Boshqa yo'llar @classmethod:

python
class Sana:
    def __init__(self, kun, oy, yil): ...

    @classmethod
    def satrdan(cls, s: str) -> "Sana":
        kun, oy, yil = map(int, s.split("."))
        return cls(kun, oy, yil)                # ⭐ cls, Sana emas

    @classmethod
    def bugun(cls) -> "Sana":
        d = date.today()
        return cls(d.day, d.month, d.year)

Nega cls(), Sana() emas:

python
class UzbekSana(Sana):
    def ozbekcha(self): ...

s = UzbekSana.satrdan("15.03.2026")
type(s)                         # UzbekSana ✅ — cls tufayli
s.ozbekcha()                    # ✅ ishlaydi

Agar Sana(...) yozilganda — UzbekSana.satrdan() ham Sana qaytarardi.

Standart kutubxonadan:

python
dict.fromkeys(["a", "b"], 0)
int.from_bytes(b"\x01", "big")
datetime.now(), datetime.fromtimestamp(0), datetime.fromisoformat(...)
Decimal.from_float(0.1)
Path.cwd(), Path.home()
frozenset.fromkeys  # yo'q, lekin naqsh bir xil

2.3. Fabrika naqshlari

A) Turli formatlar:

python
@classmethod
def satrdan(cls, s): ...
@classmethod
def jsondan(cls, j): ...
@classmethod
def fayldan(cls, yol): ...

Har birining nomi, hujjati va testi alohida.

B) Sukut konfiguratsiyalar:

python
@classmethod
def ishlab_chiqish(cls): return cls(debug=True, port=8000)
@classmethod
def ishlab_chiqarish(cls): return cls(debug=False, port=443)

C) Nusxalash va o'zgartirish:

python
@classmethod
def nusxadan(cls, boshqa, **ozgarishlar):
    m = {**boshqa.lugat(), **ozgarishlar}
    return cls(**m)

D) Registry / dispatcher:

python
@classmethod
def yarat(cls, tur: str, **kw):
    Sinf = cls._royxat[tur]
    return Sinf(**kw)

Fabrika __init__ da isinstance shoxlanishi o'rniga:

python
# ⚠️ Yomon
def __init__(self, m):
    if isinstance(m, str): ...
    elif isinstance(m, dict): ...
    elif isinstance(m, Path): ...

# ✅ Yaxshi
Sana.satrdan(...)   Sana.lugatdan(...)   Sana.fayldan(...)

2.4. classmethod va sinf holati

python
class Hisoblagich:
    _jami = 0
    _kesh: dict = {}

    @classmethod
    def statistika(cls) -> dict:
        return {"jami": cls._jami, "kesh": len(cls._kesh)}

    @classmethod
    def tozala(cls) -> None:
        """⭐ Testlar uchun."""
        cls._jami = 0
        cls._kesh.clear()

Meros bilan ehtiyot:

python
class Ota:
    _n = 0
    @classmethod
    def oshir(cls):
        cls._n += 1                     # ⚠️ AVLODGA yozadi

class Bola(Ota): pass

Bola.oshir()
Ota._n                                  # 0   ⚠️
Bola._n                                 # 1   ⚠️ yangi atribut

Umumiy hisoblagich kerak bo'lsa — aniq sinf:

python
@classmethod
def oshir(cls):
    Ota._n += 1                         # ✅ har doim Ota

2.5. @staticmethod — qachon kerak

Uch to'g'ri holat:

python
# 1. Sinf bilan mantiqan bog'liq, lekin holatga bog'liq emas
class Sana:
    @staticmethod
    def kabisami(yil: int) -> bool:
        return yil % 4 == 0 and (yil % 100 != 0 or yil % 400 == 0)

# 2. Nom fazosini tozalash (yordamchi funksiya)
class Parser:
    @staticmethod
    def _tokenla(s): ...

# 3. Avlodlar qayta aniqlashi mumkin
class Asos:
    @staticmethod
    def formatla(q): return str(q)

class Maxsus(Asos):
    @staticmethod
    def formatla(q): return f"[{q}]"

Ortiqcha holatlar:

python
# 1. Modul funksiyasi bo'lishi kerak
class Utils:
    @staticmethod
    def satr_tozala(s): return s.strip()    # ⚠️ modulga

# 2. cls kerak bo'lishi mumkin
class A:
    @staticmethod
    def yarat(): return A()                 # ⚠️ classmethod bo'lsin

Test: metod self ham, cls ham ishlatmasa — u haqiqatan shu sinfga tegishlimi?

2.6. Ikkalasi ham deskriptor

python
class classmethod:
    def __init__(self, f): self.f = f
    def __get__(self, obj, ega=None):
        if ega is None: ega = type(obj)
        return MethodType(self.f, ega)      # ⭐ SINFGA bog'lash


class staticmethod:
    def __init__(self, f): self.f = f
    def __get__(self, obj, ega=None):
        return self.f                       # ⭐ bog'lamaydi

Uchala metod turi — bir mexanizm, faqat __get__ farq qiladi:

Deskriptor __get__ qaytaradi
function MethodType(f, obj) — nusxaga bog'langan
classmethod MethodType(f, cls) — sinfga bog'langan
staticmethod f — bog'lanmagan

Turlarni ko'rish:

python
type(A.__dict__["statik"])      # <class 'staticmethod'>
type(A.statik)                  # <class 'function'>     ⭐ __get__ dan keyin
type(A.__dict__["sinf"])        # <class 'classmethod'>
type(A.sinf)                    # <class 'method'>

2.7. Kombinatsiyalar va cheklovlar

Python 3.9-3.10: classmethod + property:

python
class A:
    @classmethod
    @property
    def x(cls): return "sinf property"      # ⚠️ 3.9-3.10 da ishlardi

3.11 da olib tashlandi — chalkash va noto'g'ri ishlardi. Muqobil: metaklass yoki oddiy classmethod.

Ishlaydigan kombinatsiyalar:

python
class A:
    @classmethod
    @functools.cache                        # ✅ keshlangan fabrika
    def yarat(cls, k): return cls(k)

    @staticmethod
    @functools.lru_cache(maxsize=128)       # ✅
    def hisobla(x): return x ** 2

Tartib muhim: @classmethod eng tashqarida bo'lsin.

super() bilan:

python
class Bola(Ota):
    @classmethod
    def yarat(cls):
        return super().yarat()              # ✅ ishlaydi (cls bor)

    @staticmethod
    def f():
        return super().f()                  # ❌ RuntimeError
        return super(Bola, Bola).f()        # ✅ aniq shakl

3. Tez ma'lumotnoma

Uch tur

python
def f(self)                nusxa metod    obj.f() / A.f(obj)
@classmethod
def f(cls)                 sinf metod     A.f() / obj.f()
@staticmethod
def f()                    statik         A.f() / obj.f()

Fabrika naqshi

python
@classmethod
def satrdan(cls, s):
    return cls(...)         ⭐ cls, sinf nomi EMAS

Meros: UzbekSana.satrdan(...) → UzbekSana ✅

Deskriptorlar

function.__get__     → MethodType(f, obj)    nusxaga
classmethod.__get__  → MethodType(f, cls)    sinfga
staticmethod.__get__ → f                     bog'lanmagan

Tuzoqlar

python
return Sana(...)        ⚠️ meros buziladi
return cls(...)         ✅

cls._n += 1             ⚠️ avlodga yangi atribut
Ota._n += 1             ✅ umumiy hisoblagich

@staticmethod + super() ❌ RuntimeError
@classmethod @property  ❌ 3.11 dan olib tashlangan

4. Batafsil misollar

Misol 1 — Uch tur va deskriptorlar

python
"""self, cls va hech narsa."""

from types import MethodType

print("=== 1. Uch turning farqi ===\n")


class Namoyish:
    ATRIBUT = "sinf atributi"

    def __init__(self, nom): self.nom = nom

    def nusxa_metod(self):
        return f"nusxa: self.nom={self.nom}"

    @classmethod
    def sinf_metod(cls):
        return f"sinf: cls={cls.__name__}, cls.ATRIBUT={cls.ATRIBUT!r}"

    @staticmethod
    def statik_metod():
        return "statik: kontekst yo'q"


n = Namoyish("obyekt")

print(f"  Nusxadan chaqirish:")
for m in ["nusxa_metod", "sinf_metod", "statik_metod"]:
    print(f"    n.{m}()")
    print(f"      → {getattr(n, m)()}")

print(f"\n  Sinfdan chaqirish:")
for kod, f in [
    ("Namoyish.nusxa_metod()",   lambda: Namoyish.nusxa_metod()),
    ("Namoyish.nusxa_metod(n)",  lambda: Namoyish.nusxa_metod(n)),
    ("Namoyish.sinf_metod()",    lambda: Namoyish.sinf_metod()),
    ("Namoyish.statik_metod()",  lambda: Namoyish.statik_metod()),
]:
    try:
        natija = f"✅ {f()}"
    except TypeError as e:
        natija = f"❌ TypeError: {e}"
    print(f"    {kod:<32} {natija}")


print("\n=== ⭐ 2. Deskriptor turlari ===\n")

print(f"  {'Nom':<16} {'__dict__ da':<18} {'Sinfdan':<12} {'Nusxadan'}")
print("  " + "─" * 62)
for nom in ["nusxa_metod", "sinf_metod", "statik_metod"]:
    xom = type(Namoyish.__dict__[nom]).__name__
    sinfdan = type(getattr(Namoyish, nom)).__name__
    nusxadan = type(getattr(n, nom)).__name__
    print(f"  {nom:<16} {xom:<18} {sinfdan:<12} {nusxadan}")

print(f"""
  ⭐ __get__ NIMA QAYTARADI:

     function.__get__(obj, cls)     → MethodType(f, obj)    nusxaga
     classmethod.__get__(obj, cls)  → MethodType(f, cls)    SINFGA
     staticmethod.__get__(obj, cls) → f                     bog'lanmagan
""")

print(f"  Qo'lda tekshirish:")
for nom in ["nusxa_metod", "sinf_metod", "statik_metod"]:
    d = Namoyish.__dict__[nom]
    olingan = d.__get__(n, Namoyish)
    bogl = getattr(olingan, "__self__", "— (bog'lanmagan)")
    if hasattr(bogl, "__name__"):
        bogl = f"sinf: {bogl.__name__}"
    elif bogl != "— (bog'lanmagan)":
        bogl = f"nusxa: {bogl.nom}"
    print(f"    {nom:<16} __self__ = {bogl}")


print("\n=== ⭐ 3. Meros: cls haqiqiy sinfni biladi ===\n")


class Ota:
    NOM = "Ota"

    @classmethod
    def sinf_metod(cls):
        return f"cls={cls.__name__}, NOM={cls.NOM!r}"

    @staticmethod
    def statik_metod():
        return f"Ota.NOM={Ota.NOM!r}"       # ⚠️ qattiq yozilgan

    def nusxa_metod(self):
        return f"type(self)={type(self).__name__}"


class Bola(Ota):
    NOM = "Bola"


class Nabira(Bola):
    NOM = "Nabira"


print(f"  {'Sinf':<10} {'sinf_metod()':<32} {'statik_metod()'}")
print("  " + "─" * 68)
for S in (Ota, Bola, Nabira):
    print(f"  {S.__name__:<10} {S.sinf_metod():<32} {S.statik_metod()}")

print(f"\n  Nusxadan:")
for S in (Ota, Bola, Nabira):
    o = S()
    print(f"    {S.__name__:<10} {o.sinf_metod():<32} {o.nusxa_metod()}")

print(f"""
  ⭐ cls — CHAQIRILGAN sinf, aniqlangan sinf emas.
     Bola.sinf_metod() → cls = Bola

  ⚠️ statik_metod da Ota qattiq yozilgan — avlodda o'zgarmadi.
""")


print("=== ⭐ 4. Fabrika: cls vs sinf nomi ===\n")


class SanaYomon:
    def __init__(self, kun, oy, yil):
        self.kun, self.oy, self.yil = kun, oy, yil

    @classmethod
    def satrdan(cls, s):
        kun, oy, yil = map(int, s.split("."))
        return SanaYomon(kun, oy, yil)          # ⚠️ qattiq yozilgan

    def __repr__(self):
        return f"{type(self).__name__}({self.kun}, {self.oy}, {self.yil})"


class SanaYaxshi:
    def __init__(self, kun, oy, yil):
        self.kun, self.oy, self.yil = kun, oy, yil

    @classmethod
    def satrdan(cls, s):
        kun, oy, yil = map(int, s.split("."))
        return cls(kun, oy, yil)                # ⭐ cls

    def __repr__(self):
        return f"{type(self).__name__}({self.kun}, {self.oy}, {self.yil})"


class UzbekYomon(SanaYomon):
    OYLAR = ("yanvar", "fevral", "mart")
    def ozbekcha(self):
        return f"{self.kun}-{self.OYLAR[self.oy - 1]}"


class UzbekYaxshi(SanaYaxshi):
    OYLAR = ("yanvar", "fevral", "mart")
    def ozbekcha(self):
        return f"{self.kun}-{self.OYLAR[self.oy - 1]}"


for Sinf in (UzbekYomon, UzbekYaxshi):
    s = Sinf.satrdan("15.03.2026")
    print(f"  {Sinf.__name__}.satrdan('15.03.2026')")
    print(f"    natija: {s!r}")
    print(f"    turi:   {type(s).__name__}")
    try:
        print(f"    ozbekcha(): {s.ozbekcha()!r}   ✅")
    except AttributeError as e:
        print(f"    ozbekcha(): ❌ AttributeError: {e}")
    print()


print("=== ⚠️ 5. classmethod va sinf holati ===\n")


class Yomon:
    _n = 0

    @classmethod
    def oshir(cls):
        cls._n += 1                             # ⚠️ AVLODGA yozadi


class YomonBola(Yomon): pass


class Yaxshi:
    _n = 0

    @classmethod
    def oshir(cls):
        Yaxshi._n += 1                          # ✅ har doim Yaxshi


class YaxshiBola(Yaxshi): pass


Yomon.oshir(); YomonBola.oshir(); YomonBola.oshir()
Yaxshi.oshir(); YaxshiBola.oshir(); YaxshiBola.oshir()

print(f"  Har biriga 3 marta oshir() (1 ota, 2 avlod):\n")
print(f"  {'Yondashuv':<16} {'Ota._n':<10} {'Bola._n':<10} "
      f"{'Bola.__dict__ da'}")
print("  " + "─" * 56)
print(f"  {'cls._n += 1':<16} {Yomon._n:<10} {YomonBola._n:<10} "
      f"{'_n' in YomonBola.__dict__}")
print(f"  {'Yaxshi._n += 1':<16} {Yaxshi._n:<10} {YaxshiBola._n:<10} "
      f"{'_n' in YaxshiBola.__dict__}")

print(f"""
  ⭐ SABAB: cls._n += 1  ≡  cls._n = cls._n + 1
     1. O'QISH:  cls._n → merosdan (Ota dan)
     2. YOZISH:  cls.__dict__["_n"] = ...  ⚠️ AVLODGA

  IKKALASI HAM to'g'ri bo'lishi mumkin:
     cls._n += 1     → har avlod sinfga alohida hisoblagich
     Ota._n += 1     → butun ierarxiya uchun bitta
""")


print("=== ⚠️ 6. staticmethod va super() ===\n")


class AsosS:
    @staticmethod
    def f(): return "AsosS.f"

    @classmethod
    def g(cls): return f"AsosS.g ({cls.__name__})"


class AvlodS(AsosS):
    @staticmethod
    def f_yomon():
        try:
            return super().f()                  # ❌
        except RuntimeError as e:
            return f"❌ RuntimeError: {str(e)[:40]}"

    @staticmethod
    def f_yaxshi():
        return f"AvlodS → {super(AvlodS, AvlodS).f()}"   # ✅

    @classmethod
    def g_yaxshi(cls):
        return f"AvlodS → {super().g()}"         # ✅ ishlaydi


print(f"  @staticmethod da super():")
print(f"    {AvlodS.f_yomon()}")
print(f"    {AvlodS.f_yaxshi()}   ✅ aniq shakl")

print(f"\n  @classmethod da super():")
print(f"    {AvlodS.g_yaxshi()}   ✅ ishlaydi")

print(f"""
  ⭐ SABAB: super() ikki narsani izlaydi:
     1. __class__ yopilmasi     — ✅ bor (metod ichida)
     2. co_varnames[0]          — ⚠️ staticmethod da YO'Q

     @classmethod da cls birinchi argument → ishlaydi
""")


print("=== 7. classmethod ni qo'lda yozish ===\n")


class MeningClassmethod:
    """classmethod ning sodda amalga oshirilishi."""

    def __init__(self, f):
        self.f = f
        self.__doc__ = f.__doc__
        self.__name__ = f.__name__

    def __get__(self, obj, ega=None):
        if ega is None:
            ega = type(obj)
        return MethodType(self.f, ega)          # ⭐ SINFGA


class MeningStaticmethod:
    def __init__(self, f):
        self.f = f
        self.__doc__ = f.__doc__

    def __get__(self, obj, ega=None):
        return self.f                           # ⭐ bog'lamaydi


class Sinov:
    NOM = "Sinov"

    @MeningClassmethod
    def sinf(cls):
        """Sinf metodi."""
        return f"cls={cls.__name__}, NOM={cls.NOM}"

    @MeningStaticmethod
    def statik(x):
        """Statik metod."""
        return f"statik({x})"


class SinovBola(Sinov):
    NOM = "SinovBola"


print(f"  Sinov.sinf()       = {Sinov.sinf()}")
print(f"  SinovBola.sinf()   = {SinovBola.sinf()}   ⭐ cls to'g'ri")
print(f"  Sinov().sinf()     = {Sinov().sinf()}")
print(f"  Sinov.statik(5)    = {Sinov.statik(5)}")
print(f"  Sinov().statik(5)  = {Sinov().statik(5)}")

print(f"\n  Turlar:")
print(f"    type(Sinov.__dict__['sinf'])  = "
      f"{type(Sinov.__dict__['sinf']).__name__}")
print(f"    type(Sinov.sinf)              = {type(Sinov.sinf).__name__}")
print(f"    Sinov.sinf.__self__           = {Sinov.sinf.__self__}")

print(f"""
  ⭐ Haqiqiy classmethod/staticmethod C da yozilgan,
     lekin mantiq AYNAN shunday.
""")

Natijaning muhim qismi:

text
=== ⭐ 2. Deskriptor turlari ===

  Nom              __dict__ da        Sinfdan      Nusxadan
  ──────────────────────────────────────────────────────────────
  nusxa_metod      function           function     method
  sinf_metod       classmethod        method       method
  statik_metod     staticmethod       function     function

=== ⭐ 3. Meros: cls haqiqiy sinfni biladi ===

  Sinf       sinf_metod()                     statik_metod()
  ────────────────────────────────────────────────────────────────────
  Ota        cls=Ota, NOM='Ota'               Ota.NOM='Ota'
  Bola       cls=Bola, NOM='Bola'             Ota.NOM='Ota'
  Nabira     cls=Nabira, NOM='Nabira'         Ota.NOM='Ota'

=== ⭐ 4. Fabrika: cls vs sinf nomi ===

  UzbekYomon.satrdan('15.03.2026')
    turi:   SanaYomon
    ozbekcha(): ❌ AttributeError

  UzbekYaxshi.satrdan('15.03.2026')
    turi:   UzbekYaxshi
    ozbekcha(): '15-mart'   ✅

=== ⚠️ 5. classmethod va sinf holati ===

  Yondashuv        Ota._n     Bola._n    Bola.__dict__ da
  ────────────────────────────────────────────────────────
  cls._n += 1      1          3          True
  Yaxshi._n += 1   3          3          False

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

Misol 2 — Fabrika metodlari

python
"""@classmethod ning asosiy qo'llanishi."""

from __future__ import annotations

import json
import re
from dataclasses import dataclass, field, asdict
from datetime import date, datetime, timedelta
from pathlib import Path

print("=== 1. Turli formatlardan ===\n")


class Sana:
    """Ko'p fabrika metodi bilan sana."""

    OYLAR = ("yanvar", "fevral", "mart", "aprel", "may", "iyun",
             "iyul", "avgust", "sentabr", "oktabr", "noyabr", "dekabr")
    KUNLAR = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)

    __slots__ = ("kun", "oy", "yil")

    def __init__(self, kun: int, oy: int, yil: int):
        if not 1 <= oy <= 12:
            raise ValueError(f"Oy 1–12 oralig'ida: {oy}")
        maks = self.KUNLAR[oy - 1] + (
            1 if oy == 2 and self.kabisami(yil) else 0
        )
        if not 1 <= kun <= maks:
            raise ValueError(f"{oy}-oyda {maks} kun bor: {kun}")
        object.__setattr__(self, "kun", kun)
        object.__setattr__(self, "oy", oy)
        object.__setattr__(self, "yil", yil)

    # ═══ FABRIKA METODLARI ═══

    @classmethod
    def bugun(cls) -> "Sana":
        """Bugungi sana."""
        d = date.today()
        return cls(d.day, d.month, d.year)

    @classmethod
    def izodan(cls, s: str) -> "Sana":
        """ISO 8601: '2026-03-15'."""
        try:
            yil, oy, kun = map(int, s.strip().split("-"))
        except ValueError as e:
            raise ValueError(f"ISO format 'YYYY-MM-DD': {s!r}") from e
        return cls(kun, oy, yil)

    @classmethod
    def nuqtali(cls, s: str) -> "Sana":
        """'15.03.2026'."""
        try:
            kun, oy, yil = map(int, s.strip().split("."))
        except ValueError as e:
            raise ValueError(f"Format 'kk.oo.yyyy': {s!r}") from e
        return cls(kun, oy, yil)

    @classmethod
    def ozbekcha(cls, s: str) -> "Sana":
        """'15-mart 2026' yoki '15 mart 2026'."""
        m = re.match(r"^\s*(\d{1,2})\s*[-\s]\s*([^\s\d]+)\s+(\d{4})\s*$", s)
        if not m:
            raise ValueError(f"Format '15-mart 2026': {s!r}")
        kun, oy_nom, yil = m.groups()
        oy_nom = oy_nom.lower()
        if oy_nom not in cls.OYLAR:
            raise ValueError(f"Noma'lum oy: {oy_nom!r}")
        return cls(int(kun), cls.OYLAR.index(oy_nom) + 1, int(yil))

    @classmethod
    def timestampdan(cls, ts: float) -> "Sana":
        """Unix vaqt tamg'asidan."""
        d = datetime.fromtimestamp(ts)
        return cls(d.day, d.month, d.year)

    @classmethod
    def kunlardan(cls, n: int, boshlanish: "Sana | None" = None) -> "Sana":
        """N kundan keyingi sana."""
        b = boshlanish or cls.bugun()
        d = date(b.yil, b.oy, b.kun) + timedelta(days=n)
        return cls(d.day, d.month, d.year)

    @classmethod
    def avtomatik(cls, s: str) -> "Sana":
        """⭐ Formatni avtomatik aniqlaydi."""
        s = s.strip()
        for fabrika in (cls.izodan, cls.nuqtali, cls.ozbekcha):
            try:
                return fabrika(s)
            except ValueError:
                continue
        raise ValueError(f"Sana formatini aniqlab bo'lmadi: {s!r}")

    # ═══ STATIK YORDAMCHILAR ═══

    @staticmethod
    def kabisami(yil: int) -> bool:
        """⭐ Sinf va nusxa holatiga bog'liq EMAS."""
        return yil % 4 == 0 and (yil % 100 != 0 or yil % 400 == 0)

    @staticmethod
    def oy_kunlari(oy: int, yil: int) -> int:
        if oy == 2 and Sana.kabisami(yil):
            return 29
        return Sana.KUNLAR[oy - 1]

    # ═══ NUSXA METODLARI ═══

    def iso(self) -> str:
        return f"{self.yil:04d}-{self.oy:02d}-{self.kun:02d}"

    def ozbekcha_matn(self) -> str:
        return f"{self.kun}-{self.OYLAR[self.oy - 1]} {self.yil}"

    def __repr__(self):
        return f"{type(self).__name__}({self.kun}, {self.oy}, {self.yil})"

    def __eq__(self, b):
        if not isinstance(b, Sana): return NotImplemented
        return (self.yil, self.oy, self.kun) == (b.yil, b.oy, b.kun)

    def __lt__(self, b):
        if not isinstance(b, Sana): return NotImplemented
        return (self.yil, self.oy, self.kun) < (b.yil, b.oy, b.kun)

    def __hash__(self):
        return hash((self.yil, self.oy, self.kun))


FABRIKALAR = [
    ("Sana(15, 3, 2026)",              lambda: Sana(15, 3, 2026)),
    ("Sana.bugun()",                   lambda: Sana.bugun()),
    ("Sana.izodan('2026-03-15')",      lambda: Sana.izodan("2026-03-15")),
    ("Sana.nuqtali('15.03.2026')",     lambda: Sana.nuqtali("15.03.2026")),
    ("Sana.ozbekcha('15-mart 2026')",  lambda: Sana.ozbekcha("15-mart 2026")),
    ("Sana.timestampdan(1773532800)",  lambda: Sana.timestampdan(1773532800)),
    ("Sana.kunlardan(30, Sana(1,1,2026))",
     lambda: Sana.kunlardan(30, Sana(1, 1, 2026))),
]

for kod, f in FABRIKALAR:
    s = f()
    print(f"  {kod:<38} → {s!r}")
    print(f"  {'':<38}   {s.ozbekcha_matn()}")


print("\n\n2. ⭐ Avtomatik aniqlash:\n")

SATRLAR = ["2026-03-15", "15.03.2026", "15-mart 2026", "15 mart 2026",
           "noto'g'ri", "2026/03/15"]

for s in SATRLAR:
    try:
        natija = f"✅ {Sana.avtomatik(s)!r}"
    except ValueError as e:
        natija = f"❌ ValueError: {str(e)[:40]}"
    print(f"  {s!r:<20} {natija}")


print("\n\n3. Statik metodlar (obyektsiz):\n")

print(f"  {'Yil':<8} {'Kabisami':<12} {'Fevral kunlari'}")
print("  " + "─" * 36)
for yil in [2023, 2024, 2025, 2000, 1900, 2100]:
    print(f"  {yil:<8} {Sana.kabisami(yil)!s:<12} "
          f"{Sana.oy_kunlari(2, yil)}")

print(f"\n  ⭐ Obyekt yaratmasdan ishlaydi:")
print(f"    Sana.kabisami(2024) = {Sana.kabisami(2024)}")


print("\n\n=== ⭐ 4. Meros bilan ===\n")


class MilodiySana(Sana):
    """Qo'shimcha imkoniyatlar bilan."""

    HAFTA = ("dushanba", "seshanba", "chorshanba", "payshanba",
             "juma", "shanba", "yakshanba")

    def hafta_kuni(self) -> str:
        d = date(self.yil, self.oy, self.kun)
        return self.HAFTA[d.weekday()]

    def dam_olishmi(self) -> bool:
        return self.hafta_kuni() in ("shanba", "yakshanba")

    def __repr__(self):
        return (f"MilodiySana({self.kun}, {self.oy}, {self.yil}, "
                f"{self.hafta_kuni()})")


print(f"  ⭐ BARCHA fabrika metodlari MilodiySana qaytaradi:\n")

for kod, f in [
    ("MilodiySana.izodan('2026-03-15')",
     lambda: MilodiySana.izodan("2026-03-15")),
    ("MilodiySana.nuqtali('01.01.2026')",
     lambda: MilodiySana.nuqtali("01.01.2026")),
    ("MilodiySana.ozbekcha('25-dekabr 2026')",
     lambda: MilodiySana.ozbekcha("25-dekabr 2026")),
    ("MilodiySana.avtomatik('2026-07-04')",
     lambda: MilodiySana.avtomatik("2026-07-04")),
    ("MilodiySana.kunlardan(7, MilodiySana(1,1,2026))",
     lambda: MilodiySana.kunlardan(7, MilodiySana(1, 1, 2026))),
]:
    s = f()
    print(f"  {kod}")
    print(f"    → {s!r}")
    print(f"      turi: {type(s).__name__}, dam olish: {s.dam_olishmi()}")

print(f"""
  ⭐ Bitta ham fabrika metodini QAYTA YOZISH kerak bo'lmadi.
     cls(...) tufayli hammasi avtomatik ishlaydi.
""")


print("=== 5. Sukut konfiguratsiyalar ===\n")


@dataclass
class Sozlama:
    host: str = "localhost"
    port: int = 8000
    debug: bool = True
    ishchi: int = 1
    vaqt_chegarasi: float = 30.0
    jurnal: str = "debug"

    # ═══ FABRIKA: tayyor konfiguratsiyalar ═══

    # ⚠️ cls(port=8000, **ozgarishlar) YOZMANG: ishlab_chiqish(port=9000)
    #    → TypeError: got multiple values for keyword argument 'port'.
    #    Standart qiymatlarni lug'atda birlashtiring — o'ngdagisi yutadi.

    @classmethod
    def ishlab_chiqish(cls, **ozgarishlar) -> "Sozlama":
        return cls(**{"host": "localhost", "port": 8000, "debug": True,
                      "ishchi": 1, "jurnal": "debug", **ozgarishlar})

    @classmethod
    def sinov(cls, **ozgarishlar) -> "Sozlama":
        return cls(**{"host": "0.0.0.0", "port": 8001, "debug": True,
                      "ishchi": 2, "vaqt_chegarasi": 5.0, "jurnal": "info",
                      **ozgarishlar})

    @classmethod
    def ishlab_chiqarish(cls, **ozgarishlar) -> "Sozlama":
        return cls(**{"host": "0.0.0.0", "port": 443, "debug": False,
                      "ishchi": 8, "vaqt_chegarasi": 60.0, "jurnal": "xato",
                      **ozgarishlar})

    # ═══ FABRIKA: manbalardan ═══

    @classmethod
    def jsondan(cls, matn: str) -> "Sozlama":
        m = json.loads(matn)
        maydonlar = {f.name for f in cls.__dataclass_fields__.values()}
        notogri = set(m) - maydonlar
        if notogri:
            raise ValueError(f"Noma'lum maydonlar: {sorted(notogri)}")
        return cls(**m)

    @classmethod
    def muhitdan(cls, muhit: dict[str, str], prefiks="APP_") -> "Sozlama":
        m = {}
        for f in cls.__dataclass_fields__.values():
            kalit = f"{prefiks}{f.name.upper()}"
            if kalit not in muhit:
                continue
            xom = muhit[kalit]
            if f.type is bool or f.type == "bool":
                m[f.name] = xom.lower() in ("1", "true", "ha")
            elif f.type is int or f.type == "int":
                m[f.name] = int(xom)
            elif f.type is float or f.type == "float":
                m[f.name] = float(xom)
            else:
                m[f.name] = xom
        return cls(**m)

    # ═══ FABRIKA: nusxadan ═══

    @classmethod
    def nusxadan(cls, boshqa: "Sozlama", **ozgarishlar) -> "Sozlama":
        """⭐ Nusxa + o'zgarishlar."""
        return cls(**{**asdict(boshqa), **ozgarishlar})


print(f"  Tayyor konfiguratsiyalar:\n")
for nom in ["ishlab_chiqish", "sinov", "ishlab_chiqarish"]:
    s = getattr(Sozlama, nom)()
    print(f"    {nom:<20} port={s.port:<6} debug={s.debug!s:<6} "
          f"ishchi={s.ishchi}  jurnal={s.jurnal}")

print(f"\n  O'zgarishlar bilan:")
s = Sozlama.ishlab_chiqarish(port=8443, ishchi=16)
print(f"    ishlab_chiqarish(port=8443, ishchi=16)")
print(f"      → port={s.port}, ishchi={s.ishchi}, debug={s.debug}")

print(f"\n  JSON dan:")
s2 = Sozlama.jsondan('{"host": "wisar.uz", "port": 443, "debug": false}')
print(f"    {s2}")

try:
    Sozlama.jsondan('{"xato_maydon": 1}')
except ValueError as e:
    print(f"    Noto'g'ri maydon → ✅ ValueError: {e}")

print(f"\n  Muhitdan:")
MUHIT = {"APP_HOST": "api.wisar.uz", "APP_PORT": "3000",
         "APP_DEBUG": "false", "APP_ISHCHI": "4"}
s3 = Sozlama.muhitdan(MUHIT)
print(f"    {s3}")

print(f"\n  Nusxadan:")
s4 = Sozlama.nusxadan(s3, port=9000, debug=True)
print(f"    asl:   port={s3.port}, debug={s3.debug}")
print(f"    yangi: port={s4.port}, debug={s4.debug}")


print("\n\n=== 6. Registry fabrikasi ===\n")


class Format:
    _royxat: dict[str, type["Format"]] = {}

    def __init_subclass__(cls, /, nom: str = "", **kw):
        super().__init_subclass__(**kw)
        cls.nom = nom or cls.__name__.lower()
        Format._royxat[cls.nom] = cls

    @classmethod
    def yarat(cls, nom: str, **kw) -> "Format":
        """⭐ Registry dispatcher."""
        if nom not in cls._royxat:
            raise KeyError(
                f"Noma'lum format: {nom!r}. "
                f"Mavjud: {sorted(cls._royxat)}"
            )
        return cls._royxat[nom](**kw)

    @classmethod
    def mavjudlar(cls) -> list[str]:
        return sorted(cls._royxat)

    def yoz(self, m) -> str:
        raise NotImplementedError


class JsonFormat(Format, nom="json"):
    def __init__(self, otstup=2): self.otstup = otstup
    def yoz(self, m): return json.dumps(m, ensure_ascii=False,
                                        indent=self.otstup)


class CsvFormat(Format, nom="csv"):
    def __init__(self, ajratgich=","): self.ajratgich = ajratgich
    def yoz(self, m):
        if not m: return ""
        kalitlar = list(m[0])
        qatorlar = [self.ajratgich.join(kalitlar)]
        for q in m:
            qatorlar.append(self.ajratgich.join(str(q[k]) for k in kalitlar))
        return "\n".join(qatorlar)


class MatnFormat(Format, nom="matn"):
    def yoz(self, m):
        return "\n".join(
            " | ".join(f"{k}={v}" for k, v in q.items()) for q in m
        )


MALUMOT = [{"ism": "Aziz", "yosh": 30}, {"ism": "Malika", "yosh": 25}]

print(f"  Mavjud formatlar: {Format.mavjudlar()}\n")

for nom in Format.mavjudlar():
    f = Format.yarat(nom)
    natija = f.yoz(MALUMOT)
    print(f"  {nom}:")
    for q in natija.split("\n")[:4]:
        print(f"    {q}")
    print()

print(f"  Argumentlar bilan:")
f = Format.yarat("csv", ajratgich=";")
print(f"    Format.yarat('csv', ajratgich=';'):")
for q in f.yoz(MALUMOT).split("\n"):
    print(f"      {q}")

try:
    Format.yarat("xml")
except KeyError as e:
    print(f"\n  Format.yarat('xml') → ✅ KeyError: {e.args[0]}")

print(f"""
  ⭐ FABRIKA NAQSHLARI XULOSASI:

     1. Turli formatlar     Sana.izodan, .nuqtali, .ozbekcha
     2. Tayyor sozlamalar   Sozlama.ishlab_chiqarish()
     3. Manbalardan         .jsondan(), .muhitdan(), .fayldan()
     4. Nusxadan            .nusxadan(asl, **ozgarishlar)
     5. Registry            Format.yarat("json")
     6. Avtomatik aniqlash  Sana.avtomatik()

  ⭐ HAMMASI cls() ISHLATADI → meros avtomatik ishlaydi
""")

Natijaning muhim qismi:

text
=== 1. Turli formatlardan ===

  Sana.ozbekcha('15-mart 2026')          → Sana(15, 3, 2026)
                                           15-mart 2026
  Sana.kunlardan(30, Sana(1,1,2026))     → Sana(31, 1, 2026)

2. ⭐ Avtomatik aniqlash:

  '2026-03-15'         ✅ Sana(15, 3, 2026)
  '15-mart 2026'       ✅ Sana(15, 3, 2026)
  "noto'g'ri"          ❌ ValueError: Sana formatini aniqlab bo'lmadi

=== ⭐ 4. Meros bilan ===

  MilodiySana.izodan('2026-03-15')
    → MilodiySana(15, 3, 2026, yakshanba)
      turi: MilodiySana, dam olish: True

  ⭐ Bitta ham fabrika metodini QAYTA YOZISH kerak bo'lmadi.

=== 6. Registry fabrikasi ===

  Mavjud formatlar: ['csv', 'json', 'matn']
  Format.yarat('xml') → ✅ KeyError: Noma'lum format: 'xml'

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

Misol 3 — @staticmethod — qachon kerak

python
"""Statik metod o'rinlimi — qaror qabul qilish."""

from __future__ import annotations

import math
import re
from functools import lru_cache

print("=== ✅ 1. Sinf mantiqiga tegishli yordamchi ===\n")


class Vaqt:
    """Statik metodlar sinf mantiqining bir qismi."""

    def __init__(self, soat: int, daqiqa: int = 0, soniya: int = 0):
        jami = self.jami_soniya(soat, daqiqa, soniya)
        if not 0 <= jami < 86400:
            raise ValueError(f"Vaqt 00:00:00–23:59:59 oralig'ida")
        self.soat, self.daqiqa, self.soniya = soat, daqiqa, soniya

    @staticmethod
    def jami_soniya(soat: int, daqiqa: int, soniya: int) -> int:
        """⭐ Sof funksiya, lekin Vaqt mantiqi."""
        return soat * 3600 + daqiqa * 60 + soniya

    @staticmethod
    def soniyadan_qismlar(n: int) -> tuple[int, int, int]:
        """⭐ Teskari amal."""
        return n // 3600, (n % 3600) // 60, n % 60

    @staticmethod
    def yaroqlimi(soat: int, daqiqa: int, soniya: int) -> bool:
        """⭐ Obyekt YARATMASDAN tekshirish."""
        return (0 <= soat < 24 and 0 <= daqiqa < 60
                and 0 <= soniya < 60)

    @classmethod
    def soniyadan(cls, n: int) -> "Vaqt":
        """⭐ Fabrika — statik metodni ishlatadi."""
        return cls(*cls.soniyadan_qismlar(n % 86400))

    @classmethod
    def satrdan(cls, s: str) -> "Vaqt":
        qismlar = [int(q) for q in s.strip().split(":")]
        while len(qismlar) < 3:
            qismlar.append(0)
        return cls(*qismlar[:3])

    @property
    def soniyalarda(self) -> int:
        return self.jami_soniya(self.soat, self.daqiqa, self.soniya)

    def __add__(self, b):
        if isinstance(b, Vaqt):
            return Vaqt.soniyadan(self.soniyalarda + b.soniyalarda)
        if isinstance(b, int):
            return Vaqt.soniyadan(self.soniyalarda + b)
        return NotImplemented

    def __repr__(self):
        return f"Vaqt({self.soat}, {self.daqiqa}, {self.soniya})"

    def __str__(self):
        return f"{self.soat:02d}:{self.daqiqa:02d}:{self.soniya:02d}"


print(f"  ⭐ Obyekt YARATMASDAN ishlatish:\n")
for kod, f in [
    ("Vaqt.jami_soniya(1, 30, 0)",  lambda: Vaqt.jami_soniya(1, 30, 0)),
    ("Vaqt.soniyadan_qismlar(5400)", lambda: Vaqt.soniyadan_qismlar(5400)),
    ("Vaqt.yaroqlimi(25, 0, 0)",    lambda: Vaqt.yaroqlimi(25, 0, 0)),
    ("Vaqt.yaroqlimi(14, 30, 0)",   lambda: Vaqt.yaroqlimi(14, 30, 0)),
]:
    print(f"    {kod:<32} → {f()!r}")

print(f"\n  Fabrika metodlari statikni ishlatadi:")
for kod, f in [
    ("Vaqt.soniyadan(5400)",    lambda: Vaqt.soniyadan(5400)),
    ("Vaqt.satrdan('14:30')",   lambda: Vaqt.satrdan("14:30")),
    ("Vaqt.satrdan('9')",       lambda: Vaqt.satrdan("9")),
]:
    v = f()
    print(f"    {kod:<26} → {v!r} = {v}")

print(f"\n  Amallar:")
v = Vaqt(14, 30)
print(f"    v = {v}")
print(f"    v + Vaqt(1, 45) = {v + Vaqt(1, 45)}")
print(f"    v + 3600        = {v + 3600}")

print(f"""
  ⭐ NEGA STATIK, MODUL FUNKSIYASI EMAS:
     • jami_soniya Vaqt mantiqiga tegishli
     • Vaqt.jami_soniya(...) — o'qiganda aniq
     • Avlod sinf qayta aniqlashi mumkin
     • Nom fazosi tozalanadi
""")


print("=== ⚠️ 2. Ortiqcha statik metodlar ===\n")


class UtilsYomon:
    """⚠️ Bu — sinf emas, modul bo'lishi kerak."""

    @staticmethod
    def satr_tozala(s): return s.strip()

    @staticmethod
    def royxat_tekisla(r): return [x for a in r for x in a]

    @staticmethod
    def lugat_birlashtir(a, b): return {**a, **b}

    @staticmethod
    def son_formatla(n): return f"{n:,}"


print("""  ⚠️ class UtilsYomon:  — antipattern

     • Nusxa yaratilmaydi
     • self ham, cls ham ishlatilmaydi
     • Metodlar bir-biriga bog'liq emas
     • Bu — sinf emas, NOM FAZOSI

  ✅ To'g'ri yechim — modul:

     # utils.py
     def satr_tozala(s): return s.strip()
     def royxat_tekisla(r): ...

     # ishlatish:
     import utils
     utils.satr_tozala(s)         ✅ bir xil nom fazosi
""")

print(f"  ⭐ TEKSHIRUV SAVOLLARI:\n")
SAVOLLAR = [
    ("Sinf nusxasi yaratiladimi?",       "Yo'q → modul"),
    ("Metodlar umumiy holatga tegadimi?", "Yo'q → modul"),
    ("Avlodlar qayta aniqlaydimi?",      "Yo'q → modul"),
    ("Sinf nomi ma'no beradimi?",        "Vaqt.jami_soniya ✅"),
    ("",                                  "Utils.satr_tozala ⚠️"),
]
for savol, javob in SAVOLLAR:
    print(f"    {savol:<36} {javob}")


print("\n=== 3. Avlodlar qayta aniqlaydi ===\n")


class Hisobot:
    """⭐ Statik metod — kengaytirish nuqtasi."""

    def __init__(self, malumot: list[dict]):
        self.malumot = malumot

    @staticmethod
    def formatla_qiymat(q) -> str:
        """⭐ Avlodlar qayta aniqlashi mumkin."""
        return str(q)

    @staticmethod
    def formatla_sarlavha(s: str) -> str:
        return s.upper()

    def chiqar(self) -> str:
        if not self.malumot:
            return "(bo'sh)"
        kalitlar = list(self.malumot[0])
        qatorlar = [" | ".join(self.formatla_sarlavha(k) for k in kalitlar)]
        qatorlar.append("-" * len(qatorlar[0]))
        for q in self.malumot:
            qatorlar.append(
                " | ".join(self.formatla_qiymat(q[k]) for k in kalitlar)
            )
        return "\n".join(qatorlar)


class PulHisobot(Hisobot):
    @staticmethod
    def formatla_qiymat(q) -> str:
        if isinstance(q, (int, float)) and not isinstance(q, bool):
            return f"{q:,.2f}"
        return str(q)


class MarkdownHisobot(Hisobot):
    @staticmethod
    def formatla_sarlavha(s: str) -> str:
        return f"**{s.title()}**"

    @staticmethod
    def formatla_qiymat(q) -> str:
        return f"`{q}`"


MALUMOT = [
    {"ism": "Aziz", "maosh": 8500000},
    {"ism": "Malika", "maosh": 7000000},
]

for Sinf in (Hisobot, PulHisobot, MarkdownHisobot):
    print(f"  {Sinf.__name__}:")
    for q in Sinf(MALUMOT).chiqar().split("\n"):
        print(f"    {q}")
    print()

print(f"""  ⭐ E'TIBOR: chiqar() self.formatla_qiymat(...) chaqiradi.

     @staticmethod bo'lsa ham, self orqali chaqirilsa —
     POLIMORFIZM ishlaydi (MRO bo'ylab qidiriladi).

  ⚠️ Hisobot.formatla_qiymat(...) yozilsa — qayta aniqlash
     ISHLAMASDI.
""")


print("=== 4. staticmethod + keshlash ===\n")


class Matematika:
    @staticmethod
    @lru_cache(maxsize=256)
    def fibonachchi(n: int) -> int:
        """⭐ Statik + keshlangan."""
        if n < 2:
            return n
        return (Matematika.fibonachchi(n - 1)
                + Matematika.fibonachchi(n - 2))

    @staticmethod
    @lru_cache(maxsize=None)
    def tubmi(n: int) -> bool:
        if n < 2: return False
        if n < 4: return True
        if n % 2 == 0: return False
        for i in range(3, int(math.isqrt(n)) + 1, 2):
            if n % i == 0:
                return False
        return True

    @classmethod
    @lru_cache(maxsize=32)
    def tublar(cls, chegara: int) -> tuple[int, ...]:
        """⭐ classmethod + kesh (cls hashable bo'lishi kerak)."""
        return tuple(n for n in range(2, chegara) if cls.tubmi(n))


print(f"  fibonachchi(50) = {Matematika.fibonachchi(50):,}")
print(f"  Kesh: {Matematika.fibonachchi.cache_info()}")

print(f"\n  tublar(50) = {Matematika.tublar(50)}")
print(f"  tublar(50) (keshdan) = {Matematika.tublar(50)}")
print(f"  Kesh: {Matematika.tublar.cache_info()}")

print(f"""
  ⚠️ DEKORATOR TARTIBI:

     @staticmethod          ⭐ ENG TASHQARIDA
     @lru_cache
     def f(...): ...        ✅

     @lru_cache
     @staticmethod          ⚠️ 3.10 gacha xato
     def f(...): ...

  ⭐ 3.10+ da staticmethod chaqiriladigan bo'ldi,
     lekin tartibni to'g'ri saqlash yaxshiroq.
""")


print("=== ⚠️ 5. classmethod + property (3.11 da olib tashlandi) ===\n")

import sys

print(f"  Python versiyasi: {sys.version_info.major}."
      f"{sys.version_info.minor}\n")

print("""  Python 3.9-3.10 da ishlardi:

     class A:
         @classmethod
         @property
         def x(cls): return "sinf property"

     A.x      # 'sinf property'

  ⚠️ 3.11 da OLIB TASHLANDI. Sabablari:
     • Meros bilan noto'g'ri ishlardi
     • help() va inspect buzilardi
     • Deskriptor zanjirlanishi chalkash edi

  ✅ MUQOBILLAR:

     1. Oddiy classmethod:
        @classmethod
        def x(cls): return "..."
        A.x()                       # qavs bilan

     2. Metaklass:
        class Meta(type):
            @property
            def x(cls): return "..."
        class A(metaclass=Meta): pass
        A.x                         # ✅ qavssiz

     3. Modul darajasidagi konstanta
""")


class Meta(type):
    @property
    def tavsif(cls):
        return f"{cls.__name__} sinfi ({len(cls.__mro__)} daraja)"


class BilanMeta(metaclass=Meta):
    pass


class AvlodMeta(BilanMeta):
    pass


print(f"  Metaklass bilan:")
print(f"    BilanMeta.tavsif  = {BilanMeta.tavsif!r}")
print(f"    AvlodMeta.tavsif  = {AvlodMeta.tavsif!r}")
print(f"    ⚠️ Nusxadan ishlamaydi: ", end="")
try:
    BilanMeta().tavsif
    print("o'tdi")
except AttributeError:
    print("❌ AttributeError")


print("\n=== 6. Qaror jadvali ===\n")

print("""
  ┌────────────────────────────────┬──────────────────────┐
  │ Metod nima ishlatadi           │ Tanlov               │
  ├────────────────────────────────┼──────────────────────┤
  │ self.atribut                   │ nusxa metod          │
  │ cls(...) qaytaradi             │ ⭐ @classmethod      │
  │ cls.SINF_ATRIBUTI              │ @classmethod         │
  │ Sinf holatini o'zgartiradi     │ @classmethod         │
  │ Hech narsa (sof funksiya)      │ @staticmethod        │
  │ Faqat argumentlar              │ @staticmethod        │
  │ Umuman sinfga tegishli emas    │ ❌ modul funksiyasi  │
  └────────────────────────────────┴──────────────────────┘

  ⭐ AMALIY TARTIB:

     1. self kerakmi?          → ha → nusxa metod
     2. cls kerakmi?           → ha → @classmethod
     3. Sinf nomi ma'noli mi?  → ha → @staticmethod
                               → yo'q → modul funksiyasi
""")

Natijaning muhim qismi:

text
=== ✅ 1. Sinf mantiqiga tegishli yordamchi ===

    Vaqt.jami_soniya(1, 30, 0)       → 5400
    Vaqt.yaroqlimi(25, 0, 0)         → False

  Fabrika metodlari statikni ishlatadi:
    Vaqt.soniyadan(5400)       → Vaqt(1, 30, 0) = 01:30:00

=== 3. Avlodlar qayta aniqlaydi ===

  Hisobot:
    ISM | MAOSH
    Aziz | 8500000

  PulHisobot:
    Aziz | 8,500,000.00

  MarkdownHisobot:
    **Ism** | **Maosh**
    `Aziz` | `8500000`

=== 4. staticmethod + keshlash ===

  fibonachchi(50) = 12,586,269,025
  Kesh: CacheInfo(hits=48, misses=51, maxsize=256, currsize=51)

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

Misol 4 — Amaliy: plagin tizimi

python
"""classmethod va staticmethod bilan to'liq arxitektura."""

from __future__ import annotations

import json
import re
from abc import ABC, abstractmethod
from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Any, ClassVar

print("=== MA'LUMOT IMPORTCHISI ===\n")


@dataclass
class Yozuv:
    """Bitta ma'lumot yozuvi."""

    malumot: dict[str, Any]
    manba: str = ""
    qator: int = 0

    def __getitem__(self, k): return self.malumot[k]
    def __contains__(self, k): return k in self.malumot
    def keys(self): return self.malumot.keys()

    def __repr__(self):
        return f"Yozuv({self.malumot!r}, {self.manba!r}:{self.qator})"


class ImportXatosi(Exception):
    """Import paytidagi xato."""

    def __init__(self, xabar: str, qator: int = 0, manba: str = ""):
        self.qator, self.manba = qator, manba
        joy = f" ({manba}:{qator})" if manba else f" (qator {qator})"
        super().__init__(f"{xabar}{joy}" if qator else xabar)


class Importchi(ABC):
    """Ma'lumot importi uchun asos.

    ⭐ __init_subclass__ avlodlarni AVTOMATIK ro'yxatga oladi.
    """

    # ── Sinf atributlari (avlodlar qayta aniqlaydi) ──
    KENGAYTMALAR: ClassVar[tuple[str, ...]] = ()
    NOM: ClassVar[str] = ""
    TAVSIF: ClassVar[str] = ""

    # ── Umumiy registry ──
    _royxat: ClassVar[dict[str, type["Importchi"]]] = {}
    _kengaytma_xarita: ClassVar[dict[str, type["Importchi"]]] = {}

    def __init_subclass__(cls, **kw):
        super().__init_subclass__(**kw)
        if not cls.NOM:
            cls.NOM = cls.__name__.replace("Importchi", "").lower()
        Importchi._royxat[cls.NOM] = cls
        for k in cls.KENGAYTMALAR:
            Importchi._kengaytma_xarita[k.lower()] = cls

    # ═══ ABSTRAKT ═══

    @abstractmethod
    def tahlil(self, matn: str) -> list[Yozuv]:
        """Matnni yozuvlarga ajratadi."""

    # ═══ CLASSMETHOD: fabrikalar ═══

    @classmethod
    def nomdan(cls, nom: str, **kw) -> "Importchi":
        """Nom bo'yicha importchi yaratadi."""
        nom = nom.lower()
        if nom not in cls._royxat:
            raise KeyError(
                f"Noma'lum importchi: {nom!r}. "
                f"Mavjud: {sorted(cls._royxat)}"
            )
        return cls._royxat[nom](**kw)

    @classmethod
    def kengaytmadan(cls, yol: str | Path, **kw) -> "Importchi":
        """⭐ Fayl kengaytmasi bo'yicha."""
        k = Path(yol).suffix.lower()
        if k not in cls._kengaytma_xarita:
            raise KeyError(
                f"Kengaytma qo'llab-quvvatlanmaydi: {k!r}. "
                f"Mavjud: {sorted(cls._kengaytma_xarita)}"
            )
        return cls._kengaytma_xarita[k](**kw)

    @classmethod
    def avtomatik(cls, matn: str, **kw) -> "Importchi":
        """⭐ Mazmunni tahlil qilib formatni aniqlaydi."""
        for Sinf in cls._royxat.values():
            if Sinf.taniydimi(matn):
                return Sinf(**kw)
        raise ValueError("Formatni aniqlab bo'lmadi")

    @classmethod
    def mavjudlar(cls) -> list[tuple[str, str, tuple[str, ...]]]:
        return sorted(
            (S.NOM, S.TAVSIF, S.KENGAYTMALAR)
            for S in cls._royxat.values()
        )

    # ═══ STATICMETHOD: yordamchilar ═══

    @staticmethod
    def taniydimi(matn: str) -> bool:
        """⭐ Avlodlar qayta aniqlaydi."""
        return False

    @staticmethod
    def _tozala(q: str) -> str:
        """⭐ Umumiy tozalash — barcha avlodlar ishlatadi."""
        return q.strip().strip('"').strip("'")

    @staticmethod
    def _turga_ogir(q: str) -> Any:
        """⭐ Satrni mos turga o'giradi."""
        q = q.strip()
        if not q or q.lower() in ("null", "none", "nan"):
            return None
        if q.lower() in ("true", "ha", "yes"):
            return True
        if q.lower() in ("false", "yo'q", "no"):
            return False
        if re.fullmatch(r"-?\d+", q):
            return int(q)
        if re.fullmatch(r"-?\d*\.\d+([eE][-+]?\d+)?", q):
            return float(q)
        if re.fullmatch(r"\d{4}-\d{2}-\d{2}", q):
            try:
                return datetime.strptime(q, "%Y-%m-%d").date()
            except ValueError:
                pass
        return q

    # ═══ NUSXA METODLARI ═══

    def __init__(self, *, turga_ogir: bool = True,
                 chegara: int | None = None):
        self.turga_ogir = turga_ogir
        self.chegara = chegara
        self.xatolar: list[ImportXatosi] = []

    def yukla(self, matn: str, manba: str = "") -> list[Yozuv]:
        """⭐ Umumiy quvur — avlodlar tahlil() ni beradi."""
        self.xatolar.clear()
        yozuvlar = self.tahlil(matn)
        for i, y in enumerate(yozuvlar, 1):
            y.manba = manba or self.NOM
            y.qator = y.qator or i
            if self.turga_ogir:
                y.malumot = {
                    k: self._turga_ogir(v) if isinstance(v, str) else v
                    for k, v in y.malumot.items()
                }
        if self.chegara:
            yozuvlar = yozuvlar[:self.chegara]
        return yozuvlar

    def __repr__(self):
        return (f"{type(self).__name__}(turga_ogir={self.turga_ogir}, "
                f"chegara={self.chegara})")


# ═══ AVLODLAR ═══

class CsvImportchi(Importchi):
    KENGAYTMALAR = (".csv", ".tsv")
    NOM = "csv"
    TAVSIF = "Vergul bilan ajratilgan qiymatlar"

    def __init__(self, *, ajratgich: str = ",", **kw):
        super().__init__(**kw)
        self.ajratgich = ajratgich

    @staticmethod
    def taniydimi(matn: str) -> bool:
        qatorlar = matn.strip().split("\n")
        if len(qatorlar) < 2:
            return False
        n = qatorlar[0].count(",")
        return n > 0 and all(q.count(",") == n for q in qatorlar[:5])

    def tahlil(self, matn: str) -> list[Yozuv]:
        qatorlar = [q for q in matn.strip().split("\n") if q.strip()]
        if not qatorlar:
            return []
        sarlavhalar = [self._tozala(k)
                       for k in qatorlar[0].split(self.ajratgich)]
        natija = []
        for i, q in enumerate(qatorlar[1:], 2):
            qiymatlar = [self._tozala(v) for v in q.split(self.ajratgich)]
            if len(qiymatlar) != len(sarlavhalar):
                self.xatolar.append(ImportXatosi(
                    f"{len(sarlavhalar)} ustun kutildi, "
                    f"{len(qiymatlar)} keldi", i, self.NOM
                ))
                continue
            natija.append(Yozuv(dict(zip(sarlavhalar, qiymatlar)),
                                qator=i))
        return natija


class JsonImportchi(Importchi):
    KENGAYTMALAR = (".json",)
    NOM = "json"
    TAVSIF = "JSON massiv yoki obyekt"

    @staticmethod
    def taniydimi(matn: str) -> bool:
        s = matn.strip()
        return bool(s) and s[0] in "[{"

    def tahlil(self, matn: str) -> list[Yozuv]:
        try:
            m = json.loads(matn)
        except json.JSONDecodeError as e:
            raise ImportXatosi(f"JSON xatosi: {e.msg}", e.lineno,
                               self.NOM) from e
        if isinstance(m, dict):
            m = [m]
        if not isinstance(m, list):
            raise ImportXatosi("JSON massiv yoki obyekt bo'lsin")
        return [Yozuv(q if isinstance(q, dict) else {"qiymat": q},
                      qator=i)
                for i, q in enumerate(m, 1)]


class KalitQiymatImportchi(Importchi):
    KENGAYTMALAR = (".env", ".properties", ".ini")
    NOM = "kalit-qiymat"
    TAVSIF = "kalit=qiymat qatorlari"

    @staticmethod
    def taniydimi(matn: str) -> bool:
        qatorlar = [q for q in matn.strip().split("\n")
                    if q.strip() and not q.strip().startswith("#")]
        return bool(qatorlar) and all("=" in q for q in qatorlar[:5])

    def tahlil(self, matn: str) -> list[Yozuv]:
        m = {}
        for i, q in enumerate(matn.strip().split("\n"), 1):
            q = q.strip()
            if not q or q.startswith("#"):
                continue
            if "=" not in q:
                self.xatolar.append(
                    ImportXatosi(f"'=' topilmadi: {q!r}", i, self.NOM)
                )
                continue
            k, _, v = q.partition("=")
            m[self._tozala(k)] = self._tozala(v)
        return [Yozuv(m, qator=1)] if m else []


print("1. ⭐ Avtomatik ro'yxat:\n")

print(f"  {'Nom':<16} {'Kengaytmalar':<28} {'Tavsif'}")
print("  " + "─" * 76)
for nom, tavsif, kengaytmalar in Importchi.mavjudlar():
    print(f"  {nom:<16} {str(kengaytmalar):<28} {tavsif}")


print("\n\n2. Fabrika metodlari:\n")

MISOLLAR = {
    "csv": "ism,yosh,faol\nAziz,30,true\nMalika,25,false",
    "json": '[{"ism": "Bobur", "yosh": 40}, {"ism": "Dilnoza"}]',
    "kalit-qiymat": "# Izoh\nHOST=localhost\nPORT=8000\nDEBUG=true",
}

print(f"  a) Nom bo'yicha:")
for nom, matn in MISOLLAR.items():
    imp = Importchi.nomdan(nom)
    yozuvlar = imp.yukla(matn, manba=f"test.{nom}")
    print(f"    Importchi.nomdan({nom!r}) → {type(imp).__name__}")
    for y in yozuvlar[:2]:
        print(f"      {y.malumot}")

print(f"\n  b) Kengaytma bo'yicha:")
for yol in ["malumot.csv", "sozlama.json", ".env", "fayl.xml"]:
    try:
        imp = Importchi.kengaytmadan(yol)
        n = f"✅ {type(imp).__name__}"
    except KeyError as e:
        n = f"❌ KeyError"
    print(f"    {yol:<18} → {n}")

print(f"\n  c) ⭐ Avtomatik aniqlash:")
for nom, matn in MISOLLAR.items():
    imp = Importchi.avtomatik(matn)
    belgi = "✅" if imp.NOM == nom else "❌"
    print(f"    {nom:<16} → {type(imp).__name__:<26} {belgi}")

try:
    Importchi.avtomatik("<xml>...</xml>")
except ValueError as e:
    print(f"    {'<xml>':<16} → ❌ ValueError: {e}")


print("\n\n3. ⭐ Statik metodlar — tur o'girish:\n")

QIYMATLAR = ["42", "-17", "3.14", "1e5", "true", "ha", "false",
             "null", "", "2026-03-15", "matn", "  probel  "]

print(f"  {'Kirish':<16} {'Natija':<24} {'Tur'}")
print("  " + "─" * 52)
for q in QIYMATLAR:
    n = Importchi._turga_ogir(q)
    print(f"  {q!r:<16} {n!r:<24} {type(n).__name__}")


print("\n\n4. Tur o'girish yoqilgan/o'chirilgan:\n")

CSV = "ism,yosh,maosh,faol,sana\nAziz,30,8500000.50,true,2026-03-15"

for yoqilgan in (True, False):
    imp = Importchi.nomdan("csv", turga_ogir=yoqilgan)
    y = imp.yukla(CSV)[0]
    print(f"  turga_ogir={yoqilgan}:")
    for k, v in y.malumot.items():
        print(f"    {k:<10} {v!r:<20} {type(v).__name__}")
    print()


print("5. Xatolar bilan ishlash:\n")

BUZILGAN_CSV = ("ism,yosh,shahar\n"
                "Aziz,30,Toshkent\n"
                "Malika,25\n"
                "Bobur,40,Samarqand,ortiqcha\n"
                "Dilnoza,35,Buxoro")

imp = Importchi.nomdan("csv")
yozuvlar = imp.yukla(BUZILGAN_CSV, manba="xodimlar.csv")

print(f"  Yuklandi: {len(yozuvlar)} yozuv")
for y in yozuvlar:
    print(f"    {y.qator}: {y.malumot}")

print(f"\n  Xatolar: {len(imp.xatolar)}")
for x in imp.xatolar:
    print(f"    ❌ {x}")

print(f"\n  Buzilgan JSON:")
try:
    Importchi.nomdan("json").yukla("{buzilgan}", manba="a.json")
except ImportXatosi as e:
    print(f"    ❌ {e}")


print("\n\n6. Chegara va sozlamalar:\n")

KATTA_CSV = "n,kvadrat\n" + "\n".join(f"{i},{i*i}" for i in range(1, 21))

for chegara in [None, 3, 5]:
    imp = Importchi.nomdan("csv", chegara=chegara)
    y = imp.yukla(KATTA_CSV)
    print(f"  chegara={str(chegara):<6} → {len(y)} yozuv, "
          f"oxirgisi: {y[-1].malumot if y else '—'}")

print(f"\n  TSV (ajratgich=tab):")
TSV = "ism\tyosh\nAziz\t30"
imp = Importchi.nomdan("csv", ajratgich="\t")
print(f"    {imp.yukla(TSV)[0].malumot}")


print("\n\n7. Yangi importchi qo'shish:\n")


class XmlImportchi(Importchi):
    """⭐ Mavjud kodni O'ZGARTIRMASDAN qo'shildi."""

    KENGAYTMALAR = (".xml",)
    NOM = "xml"
    TAVSIF = "Sodda XML (bir daraja)"

    @staticmethod
    def taniydimi(matn: str) -> bool:
        return matn.strip().startswith("<")

    def tahlil(self, matn: str) -> list[Yozuv]:
        natija = []
        for i, blok in enumerate(
            re.findall(r"<yozuv>(.*?)</yozuv>", matn, re.S), 1
        ):
            m = {}
            for teg, qiymat in re.findall(r"<(\w+)>([^<]*)</\1>", blok):
                m[teg] = self._tozala(qiymat)
            if m:
                natija.append(Yozuv(m, qator=i))
        return natija


XML = """
<malumot>
  <yozuv><ism>Sardor</ism><yosh>28</yosh></yozuv>
  <yozuv><ism>Nilufar</ism><yosh>45</yosh></yozuv>
</malumot>
"""

print(f"  Yangi ro'yxat: {[n for n, _, _ in Importchi.mavjudlar()]}\n")

for kod, f in [
    ("Importchi.nomdan('xml')",         lambda: Importchi.nomdan("xml")),
    ("Importchi.kengaytmadan('a.xml')", lambda: Importchi.kengaytmadan("a.xml")),
    ("Importchi.avtomatik(XML)",        lambda: Importchi.avtomatik(XML)),
]:
    imp = f()
    print(f"  {kod:<36} → {type(imp).__name__}")

print(f"\n  Natija:")
for y in Importchi.avtomatik(XML).yukla(XML, manba="a.xml"):
    print(f"    {y}")

print(f"""

  ⭐ BU ARXITEKTURADA:

     @classmethod — FABRIKALAR:
       nomdan()          registry bo'yicha
       kengaytmadan()    fayl turi bo'yicha
       avtomatik()       mazmun tahlili bo'yicha
       mavjudlar()       introspeksiya

     @staticmethod — YORDAMCHILAR:
       taniydimi()       ⭐ avlodlar qayta aniqlaydi
       _tozala()         umumiy, holatga bog'liq emas
       _turga_ogir()     sof funksiya

     __init_subclass__:
       Avlodlarni AVTOMATIK ro'yxatga oladi
       NOM va KENGAYTMALAR ni bog'laydi

  ⭐ YANGI FORMAT QO'SHISH:
     • Sinf yozasiz
     • KENGAYTMALAR, NOM, TAVSIF beradi
     • tahlil() va taniydimi() ni yozadi
     • ⭐ MAVJUD KOD O'ZGARMAYDI
""")

Natijaning muhim qismi:

text
1. ⭐ Avtomatik ro'yxat:

  Nom              Kengaytmalar                 Tavsif
  ────────────────────────────────────────────────────────────────────────────
  csv              ('.csv', '.tsv')             Vergul bilan ajratilgan
  json             ('.json',)                   JSON massiv yoki obyekt
  kalit-qiymat     ('.env', '.properties',...)  kalit=qiymat qatorlari

2. Fabrika metodlari:

  c) ⭐ Avtomatik aniqlash:
    csv              → CsvImportchi              ✅
    json             → JsonImportchi             ✅
    kalit-qiymat     → KalitQiymatImportchi      ✅

3. ⭐ Statik metodlar — tur o'girish:

  '42'             42                       int
  'true'           True                     bool
  '2026-03-15'     datetime.date(2026, 3, 15) date
  'null'           None                     NoneType

5. Xatolar bilan ishlash:

  Yuklandi: 2 yozuv
  Xatolar: 2
    ❌ 3 ustun kutildi, 2 keldi (csv:3)

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


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

Noto'g'ri fikr To'g'risi
"cls — aniqlangan sinf" Chaqirilgan sinf
"@staticmethod va modul funksiyasi bir xil" Nom fazosi va meros farqi bor
"Fabrikada Sinf(...) yozsa bo'ladi" cls(...) — meros uchun
"cls._n += 1 umumiy hisoblagichni oshiradi" Avlodga yangi atribut
"@staticmethod da super() ishlaydi" RuntimeError
"@classmethod @property ishlaydi" 3.11 da olib tashlangan
"A.statik — staticmethod obyekti" function (__get__ dan keyin)
"@staticmethod polimorfizm bermaydi" self.f() orqali chaqirilsa — beradi

6. Keng tarqalgan xatolar va yechimlari

1. Fabrikada sinf nomini qattiq yozish

python
@classmethod
def satrdan(cls, s):
    return Sana(...)                # ⚠️ meros buziladi
    return cls(...)                 # ✅

2. cls._n += 1 bilan hisoblagich

python
@classmethod
def oshir(cls): cls._n += 1         # ⚠️ avlodga
def oshir(cls): Ota._n += 1         # ✅ umumiy

3. @staticmethod o'rniga @classmethod kerak

python
@staticmethod
def yarat(): return A()             # ⚠️
@classmethod
def yarat(cls): return cls()        # ✅

4. Utils sinfi

python
class Utils:                        # ⚠️ modul bo'lsin
    @staticmethod
    def f(x): ...

5. @staticmethod da super()

python
@staticmethod
def f(): return super().g()         # ❌
def f(): return super(B, B).g()     # ✅

6. Dekorator tartibi

python
@lru_cache
@classmethod                        # ⚠️
def f(cls): ...

@classmethod                        # ✅ tashqarida
@lru_cache
def f(cls): ...

7. __init__ da isinstance shoxlanishi

python
def __init__(self, m):
    if isinstance(m, str): ...      # ⚠️
Sana.satrdan(...)                   # ✅ fabrika

8. Statik metodni sinf nomi bilan chaqirish

python
def f(self):
    return Asos.formatla(x)         # ⚠️ qayta aniqlash ishlamaydi
    return self.formatla(x)         # ✅ polimorfizm

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 8.3-dars (o'tilgan): fabrika metodlari kirish
  • 8.5-dars: sinf atributlari va hisoblagichlar
  • 8.15-dars: deskriptorlar — ikkalasi ham deskriptor
  • 8.17-dars: dataclass va fabrika metodlari
  • 8.18-dars: ABC va __init_subclass__
  • datetime, Path, dict, int — standart kutubxonadagi fabrikalar
  • functools.lru_cache, singledispatchmethod

8. Eng yaxshi amaliyotlar

  1. Fabrikada cls() yozing. Sinf nomini qattiq yozmang.

  2. __init__ — bitta yo'l, qolgani @classmethod. isinstance shoxlanishi emas.

  3. Fabrika nomi aniq bo'lsin. satrdan, jsondan, fayldan.

  4. Sinf hisoblagichida aniq sinf. Ota._n += 1, cls._n += 1 emas.

  5. @staticmethod — faqat sinfga tegishli bo'lsa. Aks holda modul.

  6. Statik metodni self.f() bilan chaqiring. Polimorfizm saqlansin.

  7. @classmethod eng tashqi dekorator. lru_cache bilan.

  8. Tayyor konfiguratsiyalar — fabrika. Sozlama.ishlab_chiqarish().


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
1.  class A:
        @classmethod
        def f(cls): return cls.__name__
    class B(A): pass
    print(A.f(), B.f(), B().f())
2.  class A:
        @staticmethod
        def f(): return "s"
    print(A.f(), A().f())
3.  class A:
        @classmethod
        def yarat(cls): return cls()
    class B(A): pass
    print(type(B.yarat()).__name__)
4.  class A:
        @classmethod
        def yarat(cls): return A()
    class B(A): pass
    print(type(B.yarat()).__name__)
5.  class A:
        _n = 0
        @classmethod
        def f(cls): cls._n += 1
    class B(A): pass
    B.f(); B.f()
    print(A._n, B._n)
6.  class A:
        @staticmethod
        def f(): return 1
    print(type(A.__dict__["f"]).__name__, type(A.f).__name__)
7.  class A:
        @classmethod
        def f(cls): return 1
    print(type(A.__dict__["f"]).__name__, type(A.f).__name__)
8.  class A:
        def f(self): return self.g()
        @staticmethod
        def g(): return "A"
    class B(A):
        @staticmethod
        def g(): return "B"
    print(B().f())
9.  class A:
        @classmethod
        def f(cls): return cls
    print(A.f() is A, A().f() is A)
10. class A:
        @staticmethod
        def f(x): return x * 2
    print(A.f(3), A().f(3))
11. class A:
        x = 1
        @classmethod
        def f(cls): return cls.x
    class B(A): x = 2
    print(A.f(), B.f())
12. print(dict.fromkeys("ab", 0), type(dict.fromkeys("ab")))
Javoblar
  1. A B B
  2. s s
  3. B
  4. A — qattiq yozilgan
  5. 0 2 — B.__dict__ ga
  6. staticmethod function
  7. classmethod method
  8. B — self.g() orqali polimorfizm
  9. True True
  10. 6 6
  11. 1 2
  12. {'a': 0, 'b': 0} <class 'dict'>

Vazifa 2: Xatolarni tuzating

python
1.  @classmethod
    def satrdan(cls, s): return Sana(...)
2.  @staticmethod
    def yarat(): return A()
3.  @classmethod
    def oshir(cls): cls._jami += 1      # umumiy kerak
4.  class Utils:
        @staticmethod
        def tozala(s): return s.strip()
5.  @staticmethod
    def f(): return super().g()
6.  @lru_cache
    @classmethod
    def f(cls, n): ...
7.  def __init__(self, m):
        if isinstance(m, str): ...
        elif isinstance(m, dict): ...
8.  def chiqar(self): return Asos.formatla(self.x)
Javoblar
python
1.  return cls(...)
2.  @classmethod def yarat(cls): return cls()
3.  Sinf._jami += 1  (aniq sinf nomi)
4.  Modul funksiyalari qiling
5.  return super(B, B).g()
6.  @classmethod ni tashqariga
7.  Fabrika metodlari: A.satrdan(), A.lugatdan()
8.  return self.formatla(self.x)

Vazifa 3: Rang sinfi

Yozing:

  1. __init__(self, r, g, b) — 0-255 tekshiruv
  2. @classmethod hexdan("#ff5733")
  3. @classmethod hsldan(h, s, l)
  4. @classmethod nomdan("qizil")
  5. @classmethod tasodifiy()
  6. @staticmethod hex_yaroqlimi(s)
  7. Avlod RgbaRang da hammasi ishlasin

Vazifa 4: Fabrika tekshiruvchisi

Vosita yozing:

  1. @classmethod larni topsin
  2. cls(...) o'rniga sinf nomi ishlatilganini
  3. @staticmethod da cls kerakligini (obyekt qaytaradi)
  4. cls._atr += naqshini (ehtimoliy xato)
  5. Utils kabi sinflarni (faqat statik metodlar)
  6. Har biri uchun tuzatish

Vazifa 5: Singleton fabrikasi

  1. @classmethod nusxa() — har sinf uchun bitta
  2. Meros bilan to'g'ri ishlasin (har avlodga o'ziniki)
  3. tozala() — testlar uchun
  4. Thread-safe variant
  5. Argumentlar bilan keshlash (lru_cache)
  6. __new__ bilan solishtiring

Vazifa 6: Ma'lumot modeli

  1. Model asos sinfi
  2. @classmethod lugatdan(), jsondan(), royxatdan()
  3. @classmethod maydonlar() — introspeksiya
  4. @staticmethod tekshir() — avlodlar qayta aniqlaydi
  5. __init_subclass__ bilan registry
  6. Meros bilan hammasi ishlasin

Vazifa 7: O'ylash

Nega Pythonda @classmethod bor — Java va C# da faqat static metodlar bo'lsa ham?

Javob

Chunki Pythonda sinf — birinchi darajali obyekt, va cls merosda to'g'ri ishlaydigan fabrika metodlarini mumkin qiladi.

1. Java dagi muammo

java
class Sana {
    static Sana satrdan(String s) {
        return new Sana(...);           // ⚠️ Sana qattiq yozilgan
    }
}

class UzbekSana extends Sana { }

Sana s = UzbekSana.satrdan("15.03.2026");
// ⚠️ Natija — Sana, UzbekSana emas

Java da static metod sinfni bilmaydi:

  • this yo'q
  • Sinfni dinamik aniqlab bo'lmaydi
  • Meros bilan ishlamaydi

Java ning yechimlari:

java
// 1. Har avlodda qayta yozish (⚠️ takrorlanish)
class UzbekSana extends Sana {
    static UzbekSana satrdan(String s) {
        return new UzbekSana(...);
    }
}

// 2. Refleksiya (⚠️ murakkab va sekin)
static <T extends Sana> T satrdan(Class<T> cls, String s) {
    return cls.getConstructor(...).newInstance(...);
}

// 3. Abstract Factory naqshi (⚠️ ko'p kod)
interface SanaFabrika { Sana yarat(int k, int o, int y); }

Design Patterns kitobidagi "Factory Method" naqshi — aynan shu muammoni hal qilish uchun o'ylab topilgan.

2. Pythonning yechimi

python
class Sana:
    @classmethod
    def satrdan(cls, s):
        return cls(...)                 # ⭐ cls — haqiqiy sinf


class UzbekSana(Sana): pass

type(UzbekSana.satrdan("15.03.2026"))   # UzbekSana ✅

Bitta so'z (cls) butun naqshni almashtiradi.

3. Nega bu mumkin

Pythonda sinf — obyekt (8.1-darsda ko'rgan edik):

python
type(Sana)                      # <class 'type'>
Sana.__name__                   # 'Sana'
Sana(...)                       # chaqirish mumkin

f = Sana                        # o'zgaruvchiga solish
f(15, 3, 2026)                  # ✅ ishlaydi

def yarat(Sinf, *args):         # funksiyaga uzatish
    return Sinf(*args)

Java da Class<T> bor, lekin u — metama'lumot obyekti, sinfning o'zi emas:

java
Class<Sana> c = Sana.class;
c.newInstance();                // ⚠️ refleksiya, checked exception

4. cls qanday ishlaydi

classmethod — deskriptor:

python
class classmethod:
    def __get__(self, obj, ega=None):
        if ega is None:
            ega = type(obj)
        return MethodType(self.f, ega)      # ⭐ SINFGA bog'lash
python
UzbekSana.satrdan
# → Sana.__dict__["satrdan"].__get__(None, UzbekSana)
# → MethodType(f, UzbekSana)
# → chaqirilganda cls = UzbekSana ⭐

Sinf — argument sifatida uzatiladi, xuddi self kabi.

5. Amaliy foyda

a) Standart kutubxona bo'ylab:

python
dict.fromkeys("ab", 0)          # ✅
class MeningDict(dict): pass
type(MeningDict.fromkeys("ab")) # MeningDict ✅

int.from_bytes(b"\x01", "big")
class MeningInt(int): pass
type(MeningInt.from_bytes(b"\x01", "big"))  # MeningInt ✅

datetime.now(), datetime.fromisoformat(...)
Path.cwd(), Path.home()
Decimal.from_float(0.1)

Bularning hammasi @classmethod — shuning uchun meros ishlaydi.

b) __init_subclass__ bilan birga:

python
class Plagin:
    _royxat = {}

    def __init_subclass__(cls, /, nom="", **kw):
        super().__init_subclass__(**kw)
        Plagin._royxat[nom or cls.__name__] = cls

    @classmethod
    def yarat(cls, nom, **kw):
        return cls._royxat[nom](**kw)       # ⭐ registry

c) dataclass da:

python
@dataclass
class Sozlama:
    port: int = 8000

    @classmethod
    def ishlab_chiqarish(cls, **kw):
        return cls(port=443, **kw)


@dataclass
class KengaytirilganSozlama(Sozlama):
    ssl: bool = True

KengaytirilganSozlama.ishlab_chiqarish()    # ✅ to'g'ri tur

6. Boshqa tillar

Til Mexanizm
Python @classmethod + cls
Ruby self sinf metodida = sinf
Smalltalk Sinf — obyekt (Python shundan)
Java static + Class<T> refleksiya
C# static + generiklar
Kotlin companion object (qisman)
Swift class func + Self
Scala object (companion)

Ruby eng o'xshash:

ruby
class Sana
  def self.satrdan(s)
    new(...)                    # ⭐ self = chaqirilgan sinf
  end
end

class UzbekSana < Sana; end
UzbekSana.satrdan("...").class  # UzbekSana ✅

Swift ham:

swift
class Sana {
    class func satrdan(_ s: String) -> Self {
        return Self(...)        // ⭐ Self — haqiqiy tur
    }
}

Swift Self kalit so'zi aynan Python cls bilan bir xil ma'noda.

Kotlin — qisman:

kotlin
open class Sana {
    companion object {
        fun satrdan(s: String): Sana = Sana(...)  // ⚠️ meros yo'q
    }
}

Kotlin companion object meros olinmaydi — Java bilan bir xil muammo.

7. staticmethod nima uchun kerak

Agar classmethod shu qadar yaxshi bo'lsa, staticmethod nega bor?

python
class Sana:
    @staticmethod
    def kabisami(yil: int) -> bool:
        return yil % 4 == 0 and (yil % 100 != 0 or yil % 400 == 0)

Bu funksiya sinfga bog'liq emas — cls ni olish noto'g'ri signal berardi:

python
@classmethod
def kabisami(cls, yil):         # ⚠️ cls ishlatilmaydi
    return ...

O'quvchi "nega cls?" deb hayron bo'ladi.

Va staticmethod polimorfizmni ham beradi:

python
class Asos:
    @staticmethod
    def formatla(q): return str(q)

    def chiqar(self):
        return self.formatla(self.x)    # ⭐ MRO bo'ylab qidiriladi


class Maxsus(Asos):
    @staticmethod
    def formatla(q): return f"[{q}]"    # ✅ qayta aniqlandi

Modul funksiyasi bilan bu mumkin emas.

8. Tanlash qoidasi

python
class A:
    # 1. self kerak → nusxa metod
    def metod(self): return self.x

    # 2. cls kerak (yaratish/sinf holati) → classmethod
    @classmethod
    def yarat(cls): return cls()

    @classmethod
    def statistika(cls): return cls._n

    # 3. Ikkalasi ham kerak emas, lekin sinfga tegishli → staticmethod
    @staticmethod
    def tekshir(q): return q > 0

    # 4. Sinfga umuman tegishli emas → MODUL funksiyasi

9. Tarixiy izoh

classmethod va staticmethod Python 2.2 (2001) da qo'shildi — "yangi uslub sinflar" bilan birga. Undan oldin:

python
# Python 2.1 va oldin
class A:
    def yarat(cls, x):
        return cls(x)
    yarat = classmethod(yarat)      # ⚠️ dekorator sintaksisi yo'q edi

Dekorator sintaksisi (@) faqat Python 2.4 (2004) da paydo bo'ldi (PEP 318) — va uning asosiy motivatsiyasi aynan classmethod/staticmethod edi:

"The current method of applying a transformation to a function or method places the actual transformation after the function body... For longer methods, the transformation is easily missed."

Ya'ni @ — classmethod ni ko'rinadigan qilish uchun o'ylab topilgan.

10. Xulosa

@classmethod bor, chunki:

  1. Sinf — obyekt, uni argument sifatida uzatish mumkin
  2. Fabrika metodlari meros bilan to'g'ri ishlaydi (cls())
  3. Sinf holatini boshqarish kerak (registry, hisoblagich, kesh)
  4. Design Patterns naqshlarini (Factory Method) tilga kiritadi

Va staticmethod bor, chunki ba'zan metod sinfga tegishli, lekin uning holatiga bog'liq emas — cls olish noto'g'ri signal berardi.

Umumiy naqsh: Python boshqa tillarda dizayn naqshi bo'lgan narsani tilning bir qismi qiladi:

Naqsh (GoF) Pythonda
Factory Method @classmethod
Strategy Funksiya obyekti
Iterator __iter__
Decorator @dekorator
Singleton Modul
Observer weakref + callback

Shuning uchun Python kodida naqsh nomlari kamdan-kam uchraydi — ular tilga singib ketgan.

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


Xulosa

Bu darsda @staticmethod va @classmethod ni o'rgandik.

Eng muhim uch fikr:

  1. cls — chaqirilgan sinf, aniqlangan sinf emas. Bola.f() da cls Bola bo'ladi, garchi f Ota da yozilgan bo'lsa ham. Aynan shuning uchun fabrika metodida cls(...) yozing, sinf nomini emas — shunda UzbekSana.satrdan() UzbekSana qaytaradi va bitta metodni ham qayta yozish kerak bo'lmaydi.

  2. __init__ — bitta yo'l, qolgani @classmethod. isinstance shoxlanishi o'rniga Sana.satrdan(), Sana.izodan(), Sozlama.ishlab_chiqarish() — har birining nomi, hujjati va testi alohida. Standart kutubxona shunday qurilgan: dict.fromkeys, int.from_bytes, datetime.now, Path.home.

  3. cls._n += 1 avlodga yangi atribut yaratadi. O'qish merosdan, yozish esa cls.__dict__ ga boradi — shuning uchun umumiy hisoblagich uchun aniq sinf nomi (Ota._n += 1) yozing. Har avlodga alohida hisoblagich kerak bo'lsa esa cls._n += 1 to'g'ri — muhimi, buni ongli tanlash.

Keyingi darsda dataclass ni to'liq ko'ramiz: avtomatik metodlar, field() parametrlari, __post_init__, frozen, slots va qachon oddiy sinf yozish kerakligi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
8.16-dars: @staticmethod va @classmethod — IlmHamroh