IlmHamroh
Python kursi/OOP7/20-dars34 daqiqa
Mundarija (21)

8.7-dars: super()

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


1. Kirish va motivatsiya

Ko'pchilik super() ni shunday tushunadi:

python
class Bola(Ota):
    def f(self):
        return super().f()      # "ota-sinfni chaqiradi"

Bu — noto'g'ri. To'g'ri tushuncha:

super() ota-sinfni emas, MRO dagi keyingi sinfni qaytaradi.

Farq ko'p merosda ko'rinadi:

python
class A:
    def f(self): return "A"

class B(A):
    def f(self): return "B → " + super().f()

class C(A):
    def f(self): return "C → " + super().f()

class D(B, C):
    def f(self): return "D → " + super().f()


D().f()                         # 'D → B → C → A'   ⭐ B.super() → C!
B().f()                         # 'B → A'           ← bir xil kod, boshqa natija

B ning super() chaqiruvi kontekstga qarab turli sinfga boradi. B.f kodi o'zgarmagan, lekin D orqali chaqirilganda C ga boradi.

Bu darsda:

  • super() aslida nima qaytaradi
  • Argumentsiz shakli qanday ishlaydi (__class__ yopilmasi)
  • super() — MRO da keyingi, ota-sinf emas
  • super().__init__() va hamkorlikdagi meros
  • Klassik xatolar: Ota.metod(self), super(type(self), self)
  • Qachon super() argumentlar bilan

2. Nazariya — chuqur tushuntirish

2.1. super() nima qaytaradi

python
class A:
    def f(self): return "A.f"

class B(A):
    def f(self):
        s = super()
        print(type(s))          # <class 'super'>
        return s.f()

super() — proxy obyekt. U atribut qidiruvini MRO ning ma'lum joyidan boshlaydi.

Ikki shakli:

python
super(Sinf, obj)                # aniq shakl
super()                         # qisqa shakl (3.0+), faqat metod ichida

super(B, b) ma'nosi:

b obyekti uchun atribut qidir, lekin type(b).__mro__ da B dan keyin boshla.

python
class A:
    def f(self): return "A.f"

class B(A):
    def f(self): return "B.f"

class C(B):
    def f(self): return "C.f"


c = C()
C.__mro__                       # (C, B, A, object)

super(C, c).f()                 # 'B.f'   ← C dan keyin
super(B, c).f()                 # 'A.f'   ← B dan keyin
super(A, c).f()                 # AttributeError — object da f yo'q

2.2. Argumentsiz super()

python
class B(A):
    def f(self):
        return super().f()      # ≡ super(B, self).f()

Qanday ishlaydi:

Kompilyator metod ichida super() yoki __class__ ni ko'rsa, funksiyaga yashirin yopilma o'zgaruvchisi __class__ qo'shadi:

python
class B(A):
    def f(self):
        print(__class__)        # <class 'B'>  ⭐ sehrli o'zgaruvchi
        return super().f()

B.f.__code__.co_freevars        # ('__class__',)

super() ikki narsani oladi:

  1. __class__ — yopilmadan
  2. self — birinchi pozitsion argumentdan (co_varnames[0])

Shuning uchun super() ishlamaydigan joylar:

python
# 1. Sinf tashqarisida
def f(self):
    return super().f()          # ❌ RuntimeError

# 2. Statik metodda (self yo'q)
@staticmethod
def f():
    return super().f()          # ❌ RuntimeError

# 3. Ichki funksiyada
def f(self):
    def ichki():
        return super().f()      # ❌ self ko'rinmaydi
    return ichki()

# 4. Comprehension ichida (3.12 gacha)
def f(self):
    return [super().f() for _ in range(1)]   # ⚠️

Bunday joylarda aniq shakl: super(B, self).

2.3. super() — ota-sinf emas, MRO dagi keyingi

Bu — darsning eng muhim qismi.

python
class A:
    def f(self): return "A"

class B(A):
    def f(self): return "B → " + super().f()

class C(A):
    def f(self): return "C → " + super().f()

class D(B, C):
    def f(self): return "D → " + super().f()

MRO:

D.__mro__ = (D, B, C, A, object)

Chaqiruv zanjiri:

D().f()
  → D.f:  "D → " + super().f()
           super(D, d) → MRO da D dan keyin → B
  → B.f:  "B → " + super().f()
           super(B, d) → MRO da B dan keyin → C  ⭐ A EMAS!
  → C.f:  "C → " + super().f()
           super(C, d) → MRO da C dan keyin → A
  → A.f:  "A"

Natija: "D → B → C → A"

B ning kodi super().f() — u A ni chaqiraman deb o'ylaydi, lekin D kontekstida C ga boradi.

Solishtiring:

python
B().f()                         # 'B → A'      (MRO: B, A, object)
D().f()                         # 'D → B → C → A'

Bir xil kod, turli natija — super() obyektning haqiqiy turiga bog'liq.

MRO hisoblash — 8.8-darsda.

2.4. super().__init__() va hamkorlikdagi meros

python
class Asos:
    def __init__(self, **kw):
        super().__init__(**kw)          # ⭐ object.__init__()

class A(Asos):
    def __init__(self, a, **kw):
        super().__init__(**kw)          # ⭐ qolganini uzatadi
        self.a = a

class B(Asos):
    def __init__(self, b, **kw):
        super().__init__(**kw)
        self.b = b

class C(A, B):
    def __init__(self, c, **kw):
        super().__init__(**kw)
        self.c = c


C(a=1, b=2, c=3).__dict__       # {'b': 2, 'a': 1, 'c': 3}  ✅ hammasi

Hamkorlikdagi meros qoidalari:

  1. Har __init__ super().__init__() chaqirsin — hatto ota-sinf object bo'lsa ham
  2. **kwargs bilan qolgan argumentlarni uzating
  3. Nomli argumentlar ishlating — pozitsion tartib MRO da o'zgaradi
  4. Har sinf faqat o'z argumentlarini olsin

Buzilgan misol:

python
class A:
    def __init__(self, a):
        self.a = a              # ⚠️ super() yo'q

class B:
    def __init__(self, b):
        self.b = b              # ⚠️ super() yo'q

class C(A, B):
    def __init__(self, a, b):
        A.__init__(self, a)     # ⚠️ aniq chaqiruv
        B.__init__(self, b)

Bu ishlaydi, lekin:

  • MRO e'tiborga olinmaydi
  • Olmos merosda __init__ ikki marta chaqirilishi mumkin
  • Yangi sinf qo'shilsa — buziladi

2.5. Klassik xatolar

A) Ota.metod(self) — MRO ni chetlab o'tadi:

python
class B(A):
    def f(self):
        return A.f(self)        # ⚠️ super() emas

Muammo: ko'p merosda A noto'g'ri sinf bo'lishi mumkin.

Olmos merosda ikki marta chaqirish:

python
class Asos:
    def __init__(self):
        print("Asos")

class A(Asos):
    def __init__(self):
        Asos.__init__(self)     # ⚠️
        print("A")

class B(Asos):
    def __init__(self):
        Asos.__init__(self)     # ⚠️
        print("B")

class C(A, B):
    def __init__(self):
        A.__init__(self)
        B.__init__(self)

C()                             # Asos, A, Asos, B, C
                                #   ⚠️ Asos IKKI MARTA

super() bilan:

python
class A(Asos):
    def __init__(self):
        super().__init__()
        print("A")
# ...
C()                             # Asos, B, A, C   ✅ Asos BIR MARTA

B) super(type(self), self) — cheksiz rekursiya:

python
class A:
    def f(self): return "A"

class B(A):
    def f(self):
        return super(type(self), self).f()   # ⚠️

class C(B):
    pass

C().f()                         # ❌ RecursionError

Sabab: C() uchun type(self) — C, super(C, self) → B.f → yana type(self) = C → cheksiz.

super() yoki super(B, self).

C) super() ni pozitsion argumentlar bilan:

python
class A:
    def __init__(self, x): self.x = x

class B:
    def __init__(self, y): self.y = y

class C(A, B):
    def __init__(self, x, y):
        super().__init__(x)     # ⚠️ A.__init__ ga boradi
                                #    B.__init__ HECH QACHON chaqirilmaydi

Nomli argumentlar va **kwargs.

2.6. Qachon aniq shakl

python
super(Sinf, obj)                # nusxa uchun
super(Sinf, sinf2)              # sinf uchun (classmethod da)

Kerak bo'ladigan holatlar:

python
# 1. Sinf tashqarisida
def yamoq(self):
    return super(B, self).f()
B.f = yamoq

# 2. Statik kontekstda
class B(A):
    @staticmethod
    def f():
        return super(B, B).statik()

# 3. MRO ni ataylab sakrash
class C(B):
    def f(self):
        return super(B, self).f()   # B ni O'TKAZIB YUBORISH

# 4. Metaklasslarda

classmethod da:

python
class B(A):
    @classmethod
    def yarat(cls):
        return super().yarat()      # ✅ ishlaydi — cls birinchi argument

2.7. super() va boshqa metodlar

super() faqat __init__ uchun emas:

python
class Bola(Ota):
    def __repr__(self):
        return f"Bola({super().__repr__()})"

    def __eq__(self, boshqa):
        return super().__eq__(boshqa) and self.qoshimcha == boshqa.qoshimcha

    @property
    def qiymat(self):
        return super().qiymat * 2       # ⚠️ property bilan ehtiyot

    def __getattr__(self, nom):
        return super().__getattr__(nom)

@property bilan:

python
class A:
    @property
    def x(self): return 1

class B(A):
    @property
    def x(self):
        return super().x * 2            # ✅ ishlaydi

Lekin setter'ni qayta aniqlash murakkabroq:

python
class B(A):
    @A.x.setter                         # ⭐ ota-sinf property'sidan
    def x(self, q):
        self._x = q

3. Tez ma'lumotnoma

Asosiy tushuncha

super() → ota-sinf EMAS
super() → MRO da JORIY sinfdan KEYINGI sinf

super()           ≡ super(__class__, self)   (metod ichida)
super(B, obj)     obj uchun, MRO da B dan keyin
super(B, Sinf)    sinf uchun (classmethod)

Argumentsiz shakl

python
class B(A):
    def f(self):
        return super().f()

# Kompilyator qo'shadi:
#   __class__ yopilma o'zgaruvchisi
#   self — co_varnames[0] dan

⚠️ Ishlamaydi: sinf tashqarisida, @staticmethod da,
   ichki funksiyada → aniq shakl ishlating

Hamkorlikdagi meros

python
class A(Asos):
    def __init__(self, a, **kw):
        super().__init__(**kw)      ⭐ HAR DOIM
        self.a = a

Qoidalar:
  1. Har __init__ super().__init__() chaqirsin
  2. **kwargs bilan qolganini uzating
  3. Nomli argumentlar (pozitsion emas)
  4. Har sinf faqat o'z argumentini olsin

Xatolar

python
A.f(self)                       ⚠️ MRO ni chetlab o'tadi
super(type(self), self)         ❌ RecursionError
super().__init__(x)             ⚠️ ko'p merosda pozitsion

4. Batafsil misollar

Misol 1 — super() aslida nima

python
"""super() ning ichki mexanizmi."""

print("=== 1. super() — proxy obyekt ===\n")


class A:
    def f(self): return "A.f"
    def g(self): return "A.g"


class B(A):
    def f(self):
        s = super()
        print(f"      type(super()) = {type(s)}")
        print(f"      repr          = {s!r}")
        return s.f()


print(f"  B().f():")
print(f"    natija: {B().f()!r}")

b = B()
s = super(B, b)
print(f"\n  super(B, b):")
print(f"    __self__       = {s.__self__}")
print(f"    __self_class__ = {s.__self_class__.__name__}")
print(f"    __thisclass__  = {s.__thisclass__.__name__}")

print(f"""
  ⭐ super obyekti UCH narsani saqlaydi:
     __thisclass__   — qaysi sinfdan keyin boshlash ({s.__thisclass__.__name__})
     __self__        — obyekt
     __self_class__  — obyektning haqiqiy turi ({s.__self_class__.__name__})
""")


print("=== 2. MRO da joy ===\n")


class X:
    def f(self): return "X.f"

class Y(X):
    def f(self): return "Y.f"

class Z(Y):
    def f(self): return "Z.f"


z = Z()
print(f"  Z.__mro__ = {' → '.join(c.__name__ for c in Z.__mro__)}\n")

print(f"  {'Ifoda':<22} {'Natija':<10} {'Izoh'}")
print("  " + "─" * 54)
IFODALAR = [
    ("z.f()",             z.f(),             "MRO boshidan"),
    ("super(Z, z).f()",   super(Z, z).f(),   "Z dan keyin → Y"),
    ("super(Y, z).f()",   super(Y, z).f(),   "Y dan keyin → X"),
]
for kod, natija, izoh in IFODALAR:
    print(f"  {kod:<22} {natija!r:<10} {izoh}")

try:
    super(X, z).f()
except AttributeError as e:
    print(f"  {'super(X, z).f()':<22} {'❌':<10} X dan keyin → object (f yo'q)")


print("\n=== 3. ⭐ __class__ yopilmasi ===\n")


class Namoyish(A):
    def super_bilan(self):
        return super().f()

    def class_bilan(self):
        return __class__.__name__       # ⭐ sehrli o'zgaruvchi

    def ikkalasi(self):
        return f"{__class__.__name__}: {super().f()}"

    def hech_biri(self):
        return "oddiy metod"


print(f"  Metodlarning yopilma o'zgaruvchilari (co_freevars):\n")
for nom in ["super_bilan", "class_bilan", "ikkalasi", "hech_biri"]:
    f = Namoyish.__dict__[nom]
    fv = f.__code__.co_freevars
    print(f"    {nom:<16} {fv}")

n = Namoyish()
print(f"\n  Natijalar:")
print(f"    n.super_bilan()  = {n.super_bilan()!r}")
print(f"    n.class_bilan()  = {n.class_bilan()!r}")
print(f"    n.ikkalasi()     = {n.ikkalasi()!r}")

print(f"""
  ⭐ Kompilyator metod ichida super() yoki __class__ ni ko'rsa,
     funksiyaga YASHIRIN __class__ yopilma o'zgaruvchisini qo'shadi.

     super()  ≡  super(__class__, self)
                        ↑          ↑
                   yopilmadan   co_varnames[0] dan
""")


print("=== ⚠️ 4. super() ishlamaydigan joylar ===\n")

print("  A) Sinf tashqarisida:")


def tashqi_metod(self):
    try:
        return super().f()
    except RuntimeError as e:
        return f"❌ RuntimeError: {e}"


class Sinov1(A):
    pass


Sinov1.f2 = tashqi_metod
print(f"    {Sinov1().f2()}")


def tashqi_togri(self):
    return super(Sinov1, self).f()      # ✅ aniq shakl


Sinov1.f3 = tashqi_togri
print(f"    Aniq shakl: {Sinov1().f3()!r}   ✅")


print("\n  B) @staticmethod da:")


class Sinov2(A):
    @staticmethod
    def statik_yomon():
        try:
            return super().f()
        except RuntimeError as e:
            return f"❌ RuntimeError: {str(e)[:44]}"

    @staticmethod
    def statik_togri():
        return super(Sinov2, Sinov2).f      # ✅ aniq shakl


print(f"    {Sinov2.statik_yomon()}")
print(f"    Aniq shakl: {Sinov2.statik_togri()}   ✅")


print("\n  C) Ichki funksiyada:")


class Sinov3(A):
    def metod(self):
        def ichki():
            try:
                return super().f()
            except (RuntimeError, TypeError) as e:
                return f"❌ {type(e).__name__}"
        return ichki()

    def metod_togri(self):
        ota_f = super().f                   # ✅ tashqarida oling
        def ichki():
            return ota_f()
        return ichki()


print(f"    {Sinov3().metod()}")
print(f"    Aniq shakl: {Sinov3().metod_togri()!r}   ✅")


print("\n  D) @classmethod da — ✅ ISHLAYDI:")


class Sinov4(A):
    @classmethod
    def sinf_metod(cls):
        return f"{cls.__name__}: {super().f}"


print(f"    {Sinov4.sinf_metod()}")
print(f"    ⭐ cls birinchi argument — super() uni topadi")


print("\n\n=== ⚠️ 5. super(type(self), self) — rekursiya ===\n")


class Baza:
    def f(self): return "Baza.f"


class Orta(Baza):
    def f(self):
        return "Orta → " + super(type(self), self).f()      # ⚠️


class Oxirgi(Orta):
    pass


print(f"  Orta().f() = {Orta().f()!r}   ✅ ishlaydi")

try:
    Oxirgi().f()
except RecursionError:
    print(f"  Oxirgi().f() → ❌ RecursionError")

print(f"""
  ⭐ SABAB:
     Oxirgi() uchun type(self) = Oxirgi
     super(Oxirgi, self) → MRO da Oxirgi dan keyin → Orta
     Orta.f chaqiriladi → yana type(self) = Oxirgi → cheksiz

  ✅ TO'G'RI: super()  yoki  super(Orta, self)
""")


class OrtaTogri(Baza):
    def f(self):
        return "OrtaTogri → " + super().f()


class OxirgiTogri(OrtaTogri):
    pass


print(f"  OxirgiTogri().f() = {OxirgiTogri().f()!r}   ✅")

Natijaning muhim qismi:

text
=== 1. super() — proxy obyekt ===

  B().f():
      type(super()) = <class 'super'>
      repr          = <super: <class 'B'>, <B object>>
    natija: 'A.f'

  super(B, b):
    __thisclass__  = B
    __self_class__ = B

=== 2. MRO da joy ===

  Ifoda                  Natija     Izoh
  ──────────────────────────────────────────────────────
  z.f()                  'Z.f'      MRO boshidan
  super(Z, z).f()        'Y.f'      Z dan keyin → Y
  super(Y, z).f()        'X.f'      Y dan keyin → X

=== 3. ⭐ __class__ yopilmasi ===

    super_bilan      ('__class__',)
    class_bilan      ('__class__',)
    ikkalasi         ('__class__',)
    hech_biri        ()

=== ⚠️ 5. super(type(self), self) — rekursiya ===

  Orta().f() = 'Orta → Baza.f'   ✅ ishlaydi
  Oxirgi().f() → ❌ RecursionError

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

Misol 2 — super() — MRO da keyingi

python
"""Ko'p merosda super() qanday harakat qiladi."""

print("=== ⭐ 1. Olmos merosi ===\n")


class A:
    def f(self): return "A"


class B(A):
    def f(self): return "B → " + super().f()


class C(A):
    def f(self): return "C → " + super().f()


class D(B, C):
    def f(self): return "D → " + super().f()


print(f"  Ierarxiya:")
print(f"        A")
print(f"       / \\")
print(f"      B   C")
print(f"       \\ /")
print(f"        D\n")

for S in (A, B, C, D):
    mro = " → ".join(c.__name__ for c in S.__mro__)
    print(f"  {S.__name__}.__mro__ = ({mro})")
    print(f"  {S.__name__}().f()   = {S().f()!r}")
    print()

print(f"""  ⭐ ENG MUHIM KUZATUV:

     B.f kodi:  "B → " + super().f()

     B() orqali:  super(B, b) → MRO(B) = B,A,object → A
                  Natija: 'B → A'

     D() orqali:  super(B, d) → MRO(D) = D,B,C,A,object → C  ⚠️
                  Natija: 'D → B → C → A'

     BIR XIL KOD, TURLI NATIJA — chunki super() obyektning
     HAQIQIY turiga (D) qaraydi, B ning ota-sinfiga emas.
""")


print("=== 2. Qadamma-qadam kuzatuv ===\n")


class A2:
    def f(self):
        print(f"      A2.f: super() → object (f yo'q, to'xtaymiz)")
        return "A2"


class B2(A2):
    def f(self):
        keyingi = super().__self_class__.__mro__
        joy = keyingi.index(B2)
        print(f"      B2.f: MRO da B2 dan keyin → "
              f"{keyingi[joy + 1].__name__}")
        return "B2 → " + super().f()


class C2(A2):
    def f(self):
        keyingi = super().__self_class__.__mro__
        joy = keyingi.index(C2)
        print(f"      C2.f: MRO da C2 dan keyin → "
              f"{keyingi[joy + 1].__name__}")
        return "C2 → " + super().f()


class D2(B2, C2):
    def f(self):
        keyingi = type(self).__mro__
        print(f"      D2.f: MRO da D2 dan keyin → {keyingi[1].__name__}")
        return "D2 → " + super().f()


print(f"  B2().f():")
n = B2().f()
print(f"    → {n!r}\n")

print(f"  D2().f():")
n = D2().f()
print(f"    → {n!r}")


print("\n\n=== 3. ⚠️ Ota.metod(self) bilan solishtirish ===\n")


class Asos:
    def __init__(self):
        print(f"      Asos.__init__")
        self.tarix = ["Asos"]


class AliceYomon(Asos):
    def __init__(self):
        Asos.__init__(self)                 # ⚠️ aniq chaqiruv
        print(f"      Alice.__init__")
        self.tarix.append("Alice")


class BobYomon(Asos):
    def __init__(self):
        Asos.__init__(self)                 # ⚠️
        print(f"      Bob.__init__")
        self.tarix.append("Bob")


class IkkalasiYomon(AliceYomon, BobYomon):
    def __init__(self):
        AliceYomon.__init__(self)
        BobYomon.__init__(self)
        print(f"      Ikkalasi.__init__")
        self.tarix.append("Ikkalasi")


print(f"  ⚠️ Ota.metod(self) bilan:")
o1 = IkkalasiYomon()
print(f"    tarix = {o1.tarix}")
print(f"    ⚠️ Asos IKKI MARTA chaqirildi, tarix qayta yozildi\n")


class AliceYaxshi(Asos):
    def __init__(self):
        super().__init__()                  # ✅
        print(f"      Alice.__init__")
        self.tarix.append("Alice")


class BobYaxshi(Asos):
    def __init__(self):
        super().__init__()                  # ✅
        print(f"      Bob.__init__")
        self.tarix.append("Bob")


class IkkalasiYaxshi(AliceYaxshi, BobYaxshi):
    def __init__(self):
        super().__init__()                  # ✅ bitta chaqiruv
        print(f"      Ikkalasi.__init__")
        self.tarix.append("Ikkalasi")


print(f"  ✅ super() bilan:")
o2 = IkkalasiYaxshi()
print(f"    tarix = {o2.tarix}")
print(f"    ✅ Asos BIR MARTA, hamma sinf o'z hissasini qo'shdi")

print(f"""
  MRO: {' → '.join(c.__name__ for c in IkkalasiYaxshi.__mro__)}

  ⭐ super() zanjiri MRO ni TESKARI tartibda bajaradi:
     Ikkalasi → Alice → Bob → Asos → (object)
     Keyin qaytish: Asos → Bob → Alice → Ikkalasi
""")


print("\n=== 4. Mixin naqshi ===\n")


class Asos2:
    def sorov(self, yol: str) -> str:
        return f"javob({yol})"


class JurnalMixin:
    """⭐ super() bilan zanjirga ulanadi."""

    def sorov(self, yol: str) -> str:
        print(f"      [jurnal] so'rov: {yol}")
        natija = super().sorov(yol)
        print(f"      [jurnal] javob: {natija}")
        return natija


class KeshMixin:
    def __init__(self, *a, **kw):
        super().__init__(*a, **kw)
        self._kesh = {}

    def sorov(self, yol: str) -> str:
        if yol in self._kesh:
            print(f"      [kesh] URISH: {yol}")
            return self._kesh[yol]
        print(f"      [kesh] o'tkazish: {yol}")
        natija = super().sorov(yol)
        self._kesh[yol] = natija
        return natija


class QaytaUrinishMixin:
    def sorov(self, yol: str) -> str:
        for urinish in range(1, 4):
            try:
                return super().sorov(yol)
            except Exception:
                print(f"      [urinish {urinish}] xato")
        raise RuntimeError("3 urinish ham muvaffaqiyatsiz")


class Xizmat(JurnalMixin, KeshMixin, QaytaUrinishMixin, Asos2):
    """⭐ Mixinlar TARTIBI muhim."""


print(f"  MRO: {' → '.join(c.__name__ for c in Xizmat.__mro__)}\n")

x = Xizmat()
print(f"  Birinchi so'rov (/api):")
x.sorov("/api")

print(f"\n  Ikkinchi so'rov (/api) — keshdan:")
x.sorov("/api")

print(f"""
  ⭐ MIXIN NAQSHI:
     Har mixin super() ni chaqiradi → zanjir hosil bo'ladi.
     Tartibni o'zgartirsangiz — xatti-harakat o'zgaradi:

       (Jurnal, Kesh, ...)  → jurnal keshdan OLDIN
       (Kesh, Jurnal, ...)  → jurnal faqat kesh o'tkazganda
""")


class Xizmat2(KeshMixin, JurnalMixin, QaytaUrinishMixin, Asos2):
    pass


print(f"  Tartib o'zgartirildi: KeshMixin, JurnalMixin, ...\n")
x2 = Xizmat2()
print(f"  Birinchi so'rov:")
x2.sorov("/api")
print(f"\n  Ikkinchi so'rov — keshdan (jurnal YO'Q):")
x2.sorov("/api")


print("\n\n=== 5. super() zanjiri to'xtashi ===\n")


class P1:
    def f(self):
        print(f"      P1.f — super() CHAQIRMAYDI")
        return "P1"


class P2:
    def f(self):
        print(f"      P2.f")
        return "P2 → " + super().f()


class P3:
    def f(self):
        print(f"      P3.f")
        return "P3"


class Yakun(P2, P1, P3):
    def f(self):
        print(f"      Yakun.f")
        return "Yakun → " + super().f()


print(f"  MRO: {' → '.join(c.__name__ for c in Yakun.__mro__)}\n")
n = Yakun().f()
print(f"\n  Natija: {n!r}")
print(f"  ⚠️ P3.f CHAQIRILMADI — P1 zanjirni to'xtatdi")

print(f"""
  ⭐ QOIDA: hamkorlikdagi merosda HAR sinf super() ni
     chaqirishi kerak — aks holda zanjir uziladi.

     Faqat ENG OXIRGI sinf (odatda Asos) super() ni
     chaqirmasligi mumkin — yoki object ga uzatadi.
""")

Natijaning muhim qismi:

text
=== ⭐ 1. Olmos merosi ===

  B.__mro__ = (B → A → object)
  B().f()   = 'B → A'

  D.__mro__ = (D → B → C → A → object)
  D().f()   = 'D → B → C → A'

=== 3. ⚠️ Ota.metod(self) bilan solishtirish ===

  ⚠️ Ota.metod(self) bilan:
      Asos.__init__
      Alice.__init__
      Asos.__init__
      Bob.__init__
    tarix = ['Asos', 'Bob', 'Ikkalasi']
    ⚠️ Asos IKKI MARTA chaqirildi, tarix qayta yozildi

  ✅ super() bilan:
      Asos.__init__
      Bob.__init__
      Alice.__init__
    tarix = ['Asos', 'Bob', 'Alice', 'Ikkalasi']

=== 4. Mixin naqshi ===

  MRO: Xizmat → JurnalMixin → KeshMixin → QaytaUrinishMixin → Asos2

  Ikkinchi so'rov (/api) — keshdan:
      [jurnal] so'rov: /api
      [kesh] URISH: /api
      [jurnal] javob: javob(/api)

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

Misol 3 — Hamkorlikdagi __init__

python
"""Ko'p merosda konstruktorlarni to'g'ri bog'lash."""

print("=== ⚠️ 1. Buzilgan yondashuv ===\n")


class AYomon:
    def __init__(self, a):
        self.a = a
        print(f"      A.__init__(a={a})")


class BYomon:
    def __init__(self, b):
        self.b = b
        print(f"      B.__init__(b={b})")


class CYomon(AYomon, BYomon):
    def __init__(self, a, b):
        super().__init__(a)             # ⚠️ faqat A ga boradi


print(f"  CYomon(1, 2):")
c = CYomon(1, 2)
print(f"    __dict__ = {c.__dict__}")
print(f"    ⚠️ B.__init__ CHAQIRILMADI — b atributi yo'q\n")

print(f"  MRO: {' → '.join(k.__name__ for k in CYomon.__mro__)}")


print("\n\n=== ✅ 2. Hamkorlikdagi meros ===\n")


class Asos:
    """⭐ Zanjirning oxiri — object ga uzatadi."""

    def __init__(self, **kw):
        if kw:
            print(f"      Asos: qolgan argumentlar {kw}")
        super().__init__()              # object.__init__()
        print(f"      Asos.__init__")


class A(Asos):
    def __init__(self, a, **kw):
        super().__init__(**kw)          # ⭐ qolganini uzatadi
        self.a = a
        print(f"      A.__init__(a={a})")


class B(Asos):
    def __init__(self, b, **kw):
        super().__init__(**kw)
        self.b = b
        print(f"      B.__init__(b={b})")


class C(Asos):
    def __init__(self, c, **kw):
        super().__init__(**kw)
        self.c = c
        print(f"      C.__init__(c={c})")


class Hammasi(A, B, C):
    def __init__(self, **kw):
        super().__init__(**kw)
        print(f"      Hammasi.__init__")


print(f"  MRO: {' → '.join(k.__name__ for k in Hammasi.__mro__)}\n")
print(f"  Hammasi(a=1, b=2, c=3):")
h = Hammasi(a=1, b=2, c=3)
print(f"\n    __dict__ = {h.__dict__}   ✅ hammasi bor")

print(f"""
  ⭐ QOIDALAR:
     1. Har __init__ super().__init__(**kw) chaqirsin
     2. Har sinf o'z argumentini NOMLI oladi
     3. Qolgani **kw orqali uzatiladi
     4. Zanjir oxiridagi sinf super().__init__() (argumentsiz)
""")


print("\n=== 3. Turli kombinatsiyalar ===\n")


class FaqatAB(A, B):
    def __init__(self, **kw):
        super().__init__(**kw)


class FaqatBC(B, C):
    def __init__(self, **kw):
        super().__init__(**kw)


class Teskari(C, B, A):
    def __init__(self, **kw):
        super().__init__(**kw)


KOMBINATSIYALAR = [
    (FaqatAB, {"a": 1, "b": 2}),
    (FaqatBC, {"b": 2, "c": 3}),
    (Teskari, {"a": 1, "b": 2, "c": 3}),
]

for Sinf, kw in KOMBINATSIYALAR:
    print(f"  {Sinf.__name__}({', '.join(f'{k}={v}' for k, v in kw.items())}):")
    print(f"    MRO: {' → '.join(k.__name__ for k in Sinf.__mro__[:-2])}")
    obj = Sinf(**kw)
    print(f"    __dict__ = {obj.__dict__}\n")


print("=== ⚠️ 4. Xato: noto'g'ri argument ===\n")

print(f"  Hammasi(a=1, b=2, c=3, xato=4):")
try:
    Hammasi(a=1, b=2, c=3, xato=4)
except TypeError as e:
    print(f"    ⚠️ Chaqirilmadi (Asos qolgan argumentni yutdi)")

print(f"""
  ⚠️ Asos ichida kw ni tekshirmasak, xato JIMGINA o'tib ketadi.

  ✅ TO'G'RI Asos:

     class Asos:
         def __init__(self, **kw):
             if kw:
                 raise TypeError(
                     f"Noma'lum argumentlar: {{sorted(kw)}}"
                 )
             super().__init__()
""")


class AsosQatiy:
    def __init__(self, **kw):
        if kw:
            raise TypeError(f"Noma'lum argumentlar: {sorted(kw)}")
        super().__init__()


class A2(AsosQatiy):
    def __init__(self, a, **kw):
        super().__init__(**kw)
        self.a = a


class B2(AsosQatiy):
    def __init__(self, b, **kw):
        super().__init__(**kw)
        self.b = b


class C2(A2, B2):
    def __init__(self, **kw):
        super().__init__(**kw)


print(f"  Qat'iy Asos bilan:")
print(f"    C2(a=1, b=2)         → {C2(a=1, b=2).__dict__}   ✅")
try:
    C2(a=1, b=2, xato=3)
except TypeError as e:
    print(f"    C2(a=1, b=2, xato=3) → ✅ TypeError: {e}")


print("\n\n=== 5. Ustuvorlikni to'g'ri o'rnatish ===\n")


class Sozlama:
    """Zanjir bo'ylab sozlamalarni yig'adi."""

    def __init__(self, **kw):
        self._d: dict = {}
        super().__init__(**kw) if kw else None
        self._birlashtir()

    def _birlashtir(self):
        """MRO ni TESKARI aylanib sozlamalarni yig'adi."""
        for Sinf in reversed(type(self).__mro__):
            self._d.update(getattr(Sinf, "SOZLAMA", {}))

    def __repr__(self):
        return f"{type(self).__name__}({self._d})"


class Asosiy(Sozlama):
    SOZLAMA = {"host": "localhost", "port": 8000, "debug": False}


class Xavfsizlik(Sozlama):
    SOZLAMA = {"ssl": True, "port": 443}


class IshlabChiqarish(Sozlama):
    SOZLAMA = {"debug": False, "jurnal": "xato"}


class Prod(IshlabChiqarish, Xavfsizlik, Asosiy):
    SOZLAMA = {"host": "wisar.uz"}


class Dev(Asosiy):
    SOZLAMA = {"debug": True, "jurnal": "hammasi"}


for Sinf in (Asosiy, Prod, Dev):
    obj = Sinf()
    mro = " → ".join(k.__name__ for k in Sinf.__mro__[:-2])
    print(f"  {Sinf.__name__:<10} MRO: {mro}")
    print(f"  {'':<10} {obj._d}\n")

print(f"""  ⭐ reversed(MRO) bilan yig'ish:
     Eng UZOQ ota-sinfdan boshlab, har biri ustidan yozadi.
     Natija: eng YAQIN sinf ustuvor.

     Prod: Asosiy → Xavfsizlik → IshlabChiqarish → Prod
           port: 8000 → 443 → 443 → 443
           host: localhost → ... → wisar.uz
""")


print("=== 6. __init_subclass__ va super() ===\n")


class Kuzatuv:
    _sinflar: list[str] = []

    def __init_subclass__(cls, /, teg: str = "", **kw):
        super().__init_subclass__(**kw)      # ⭐ SHART
        cls.teg = teg or cls.__name__.lower()
        Kuzatuv._sinflar.append(f"{cls.__name__}({cls.teg})")


class Aralash:
    def __init_subclass__(cls, /, versiya: int = 1, **kw):
        super().__init_subclass__(**kw)      # ⭐ zanjir davom etadi
        cls.versiya = versiya


class Birlashgan(Kuzatuv, Aralash, teg="asos", versiya=2):
    pass


class Avlod(Birlashgan, teg="avlod", versiya=3):
    pass


print(f"  Ro'yxat: {Kuzatuv._sinflar}")
print(f"\n  {'Sinf':<14} {'teg':<10} {'versiya'}")
print("  " + "─" * 34)
for S in (Birlashgan, Avlod):
    print(f"  {S.__name__:<14} {S.teg:<10} {S.versiya}")

print(f"""
  ⭐ __init_subclass__ da ham super() chaqirish SHART —
     aks holda boshqa mixinlar ishlamaydi.

     Argumentlar **kw orqali zanjir bo'ylab uzatiladi.
""")

Natijaning muhim qismi:

text
=== ⚠️ 1. Buzilgan yondashuv ===

  CYomon(1, 2):
      A.__init__(a=1)
    __dict__ = {'a': 1}
    ⚠️ B.__init__ CHAQIRILMADI — b atributi yo'q

=== ✅ 2. Hamkorlikdagi meros ===

  MRO: Hammasi → A → B → C → Asos → object

  Hammasi(a=1, b=2, c=3):
      Asos.__init__
      C.__init__(c=3)
      B.__init__(b=2)
      A.__init__(a=1)
      Hammasi.__init__

    __dict__ = {'c': 3, 'b': 2, 'a': 1}   ✅ hammasi bor

=== 5. Ustuvorlikni to'g'ri o'rnatish ===

  Prod       MRO: Prod → IshlabChiqarish → Xavfsizlik → Asosiy
             {'host': 'wisar.uz', 'port': 443, 'debug': False,
              'ssl': True, 'jurnal': 'xato'}

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

Misol 4 — Amaliy: qatlamli xizmat

python
"""super() bilan qurilgan mixin arxitekturasi."""

from __future__ import annotations

import time
import json
from typing import Any

print("=== QATLAMLI XIZMAT ===\n")


class Xizmat:
    """Asos — haqiqiy ish shu yerda."""

    def __init__(self, nom: str = "xizmat", **kw):
        if kw:
            raise TypeError(f"Noma'lum argumentlar: {sorted(kw)}")
        super().__init__()
        self.nom = nom
        self._chaqiruvlar = 0

    def sorov(self, yol: str, **params: Any) -> dict:
        """Haqiqiy so'rov."""
        self._chaqiruvlar += 1
        time.sleep(0.001)
        if yol == "/xato":
            raise ConnectionError("Tarmoq mavjud emas")
        return {"yol": yol, "params": params, "n": self._chaqiruvlar}

    def __repr__(self):
        return f"{type(self).__name__}({self.nom!r})"


class JurnalMixin:
    """Har so'rovni yozib boradi."""

    def __init__(self, *, jurnal_darajasi: str = "info", **kw):
        super().__init__(**kw)                  # ⭐
        self.jurnal_darajasi = jurnal_darajasi
        self.jurnal: list[str] = []

    def sorov(self, yol: str, **params: Any) -> dict:
        self.jurnal.append(f"→ {yol} {params}")
        try:
            natija = super().sorov(yol, **params)    # ⭐
            self.jurnal.append(f"← ok {natija['n']}")
            return natija
        except Exception as e:
            self.jurnal.append(f"← XATO {type(e).__name__}")
            raise


class KeshMixin:
    """Natijalarni keshlaydi."""

    def __init__(self, *, kesh_hajmi: int = 100, **kw):
        super().__init__(**kw)
        self.kesh_hajmi = kesh_hajmi
        self._kesh: dict[str, dict] = {}
        self.urish = 0
        self.otkazish = 0

    def _kalit(self, yol: str, params: dict) -> str:
        return f"{yol}?{json.dumps(params, sort_keys=True)}"

    def sorov(self, yol: str, **params: Any) -> dict:
        kalit = self._kalit(yol, params)
        if kalit in self._kesh:
            self.urish += 1
            return self._kesh[kalit]
        self.otkazish += 1
        natija = super().sorov(yol, **params)
        if len(self._kesh) >= self.kesh_hajmi:
            self._kesh.pop(next(iter(self._kesh)))       # eng eskisi
        self._kesh[kalit] = natija
        return natija

    def kesh_holati(self) -> dict:
        jami = self.urish + self.otkazish
        return {"hajm": len(self._kesh), "urish": self.urish,
                "otkazish": self.otkazish,
                "nisbat": f"{self.urish / jami:.0%}" if jami else "—"}


class QaytaUrinishMixin:
    """Xato bo'lsa qayta urinadi."""

    def __init__(self, *, urinishlar: int = 3, kutish: float = 0.001, **kw):
        super().__init__(**kw)
        self.urinishlar = urinishlar
        self.kutish = kutish
        self.qayta_urinishlar = 0

    def sorov(self, yol: str, **params: Any) -> dict:
        oxirgi: Exception | None = None
        for n in range(1, self.urinishlar + 1):
            try:
                return super().sorov(yol, **params)
            except (ConnectionError, TimeoutError) as e:
                oxirgi = e
                if n < self.urinishlar:
                    self.qayta_urinishlar += 1
                    time.sleep(self.kutish * n)
        raise RuntimeError(
            f"{self.urinishlar} urinish muvaffaqiyatsiz"
        ) from oxirgi


class OlchovMixin:
    """Vaqtni o'lchaydi."""

    def __init__(self, **kw):
        super().__init__(**kw)
        self.olchovlar: list[float] = []

    def sorov(self, yol: str, **params: Any) -> dict:
        boshlanish = time.perf_counter()
        try:
            return super().sorov(yol, **params)
        finally:
            self.olchovlar.append(time.perf_counter() - boshlanish)

    def olchov_holati(self) -> dict:
        if not self.olchovlar:
            return {"soni": 0}
        return {
            "soni": len(self.olchovlar),
            "jami_ms": f"{sum(self.olchovlar) * 1000:.1f}",
            "ortacha_ms": f"{sum(self.olchovlar) / len(self.olchovlar) * 1000:.2f}",
            "maks_ms": f"{max(self.olchovlar) * 1000:.2f}",
        }


class ChegaraMixin:
    """So'rovlar sonini cheklaydi."""

    def __init__(self, *, chegara: int = 1000, **kw):
        super().__init__(**kw)
        self.chegara = chegara
        self._soni = 0

    def sorov(self, yol: str, **params: Any) -> dict:
        if self._soni >= self.chegara:
            raise RuntimeError(f"Chegara oshdi: {self.chegara}")
        self._soni += 1
        return super().sorov(yol, **params)


# ═══ KOMBINATSIYALAR ═══

class ToliqXizmat(OlchovMixin, JurnalMixin, KeshMixin,
                  QaytaUrinishMixin, ChegaraMixin, Xizmat):
    """Barcha qatlamlar."""


class OddiyXizmat(KeshMixin, Xizmat):
    """Faqat kesh."""


class IshonchliXizmat(QaytaUrinishMixin, JurnalMixin, Xizmat):
    """Qayta urinish + jurnal."""


print("1. MRO — qatlam tartibi:\n")

for Sinf in (ToliqXizmat, OddiyXizmat, IshonchliXizmat):
    mro = " → ".join(c.__name__ for c in Sinf.__mro__[:-1])
    print(f"  {Sinf.__name__}:")
    print(f"    {mro}\n")


print("2. Hamkorlikdagi __init__:\n")

x = ToliqXizmat(
    nom="asosiy",
    jurnal_darajasi="debug",
    kesh_hajmi=50,
    urinishlar=2,
    chegara=100,
)

print(f"  {x!r}")
print(f"  Barcha argumentlar zanjir bo'ylab taqsimlandi:\n")
for atr in ["nom", "jurnal_darajasi", "kesh_hajmi", "urinishlar", "chegara"]:
    print(f"    {atr:<20} {getattr(x, atr)!r}")

try:
    ToliqXizmat(notogri=1)
except TypeError as e:
    print(f"\n  ToliqXizmat(notogri=1) → ✅ TypeError: {e}")


print("\n\n3. So'rovlar zanjiri:\n")

SOROVLAR = [
    ("/api/users", {"limit": 10}),
    ("/api/users", {"limit": 10}),          # kesh
    ("/api/posts", {}),
    ("/api/users", {"limit": 20}),          # boshqa params
    ("/api/posts", {}),                     # kesh
]

for yol, params in SOROVLAR:
    natija = x.sorov(yol, **params)
    print(f"  {yol:<16} {str(params):<16} → n={natija['n']}")

print(f"\n  Kesh:   {x.kesh_holati()}")
print(f"  Olchov: {x.olchov_holati()}")
print(f"\n  Jurnal ({len(x.jurnal)} yozuv):")
for q in x.jurnal[:8]:
    print(f"    {q}")


print("\n\n4. Xato va qayta urinish:\n")

x2 = IshonchliXizmat(nom="ishonchli", urinishlar=3)

try:
    x2.sorov("/xato")
except RuntimeError as e:
    print(f"  x2.sorov('/xato') → ✅ RuntimeError: {e}")
    print(f"    sabab: {type(e.__cause__).__name__}: {e.__cause__}")

print(f"    qayta urinishlar: {x2.qayta_urinishlar}")
print(f"\n  Jurnal:")
for q in x2.jurnal:
    print(f"    {q}")


print("\n\n5. ⭐ Tartib xatti-harakatni o'zgartiradi:\n")


class KeshOldin(KeshMixin, JurnalMixin, Xizmat):
    """Kesh birinchi — keshdan kelsa jurnal YO'Q."""


class JurnalOldin(JurnalMixin, KeshMixin, Xizmat):
    """Jurnal birinchi — hamma so'rov yoziladi."""


for Sinf in (KeshOldin, JurnalOldin):
    s = Sinf(nom="t")
    s.sorov("/a")
    s.sorov("/a")                           # kesh
    s.sorov("/a")                           # kesh
    print(f"  {Sinf.__name__:<14} 3 so'rov (2 tasi keshdan)")
    print(f"  {'':<14}   jurnal yozuvlari: {len(s.jurnal)}")
    print(f"  {'':<14}   kesh urish: {s.urish}, o'tkazish: {s.otkazish}\n")

print(f"""  ⭐ KeshOldin:   MRO da Kesh birinchi → keshdan qaytsa
                  Jurnal ga umuman bormaydi (1 yozuv)

     JurnalOldin: MRO da Jurnal birinchi → har so'rov
                  yoziladi (3 × 2 = 6 yozuv)
""")


print("=== 6. Qatlamlarni tekshirish ===\n")


def qatlamlarni_korsat(Sinf: type) -> None:
    """Qaysi qatlam qaysi metodni ushlaydi."""
    print(f"  {Sinf.__name__}:")
    for metod in ["__init__", "sorov"]:
        egalar = [c.__name__ for c in Sinf.__mro__
                  if metod in c.__dict__ and c is not object]
        print(f"    {metod:<12} {' → '.join(egalar)}")
    print()


for Sinf in (ToliqXizmat, OddiyXizmat, IshonchliXizmat):
    qatlamlarni_korsat(Sinf)

print(f"""
  ⭐ BU ARXITEKTURA NEGA ISHLAYDI:

     1. Har mixin super() ni chaqiradi → zanjir uzilmaydi
     2. Har __init__ **kw bilan qolganini uzatadi
     3. Har mixin O'Z argumentini NOMLI oladi
     4. Asos sinf noma'lum argumentni ANIQLAYDI
     5. Mixinlar bir-birini BILMAYDI — faqat super()
     6. Tartibni o'zgartirish — xatti-harakatni o'zgartiradi

  ⚠️ CHEKLOVLARI:
     • MRO ni tushunish kerak (8.8-dars)
     • Nosozlikni topish qiyinroq
     • Mixin tartibi hujjatlanishi shart
     • Ko'p qatlam → sekinlashish
""")

Natijaning muhim qismi:

text
1. MRO — qatlam tartibi:

  ToliqXizmat:
    ToliqXizmat → OlchovMixin → JurnalMixin → KeshMixin →
    QaytaUrinishMixin → ChegaraMixin → Xizmat

2. Hamkorlikdagi __init__:

  ToliqXizmat('asosiy')
  Barcha argumentlar zanjir bo'ylab taqsimlandi:

    nom                  'asosiy'
    jurnal_darajasi      'debug'
    kesh_hajmi           50
    urinishlar           2

  ToliqXizmat(notogri=1) → ✅ TypeError: Noma'lum argumentlar: ['notogri']

3. So'rovlar zanjiri:

  Kesh:   {'hajm': 3, 'urish': 2, 'otkazish': 3, 'nisbat': '40%'}
  Olchov: {'soni': 5, 'jami_ms': '5.1', 'ortacha_ms': '1.02', 'maks_ms': '1.76'}

5. ⭐ Tartib xatti-harakatni o'zgartiradi:

  KeshOldin      3 so'rov (2 tasi keshdan)
                   jurnal yozuvlari: 2
  JurnalOldin    3 so'rov (2 tasi keshdan)
                   jurnal yozuvlari: 6

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


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

Noto'g'ri fikr To'g'risi
"super() ota-sinfni chaqiradi" MRO da keyingi sinfni
"super() — funksiya chaqiruvi" Proxy obyekt qaytaradi
"super() har joyda ishlaydi" Metod ichida, self bilan
"Ota.metod(self) — super() bilan bir xil" MRO ni chetlab o'tadi
"super(type(self), self) — to'g'ri shakl" RecursionError
"Bitta meros bo'lsa farq yo'q" To'g'ri, lekin avlod qo'shilsa farq paydo bo'ladi
"super() faqat __init__ uchun" Har metod uchun
"@staticmethod da super() ishlaydi" self/cls yo'q

6. Keng tarqalgan xatolar va yechimlari

1. super().__init__() unutish

python
class B(A):
    def __init__(self, x, y):
        self.y = y                      # ⚠️
        super().__init__(x)             # ✅

2. Ota.__init__(self) ishlatish

python
Asos.__init__(self)                     # ⚠️ olmosda ikki marta
super().__init__()                      # ✅

3. super(type(self), self)

python
super(type(self), self).f()             # ❌ RecursionError
super().f()                             # ✅

4. Ko'p merosda pozitsion argument

python
super().__init__(x, y)                  # ⚠️ faqat birinchi sinfga
super().__init__(x=x, **kw)             # ✅

5. Zanjirni uzish

python
class Mixin:
    def f(self):
        return "mixin"                  # ⚠️ super() yo'q
        return "mixin " + super().f()   # ✅

6. @staticmethod da super()

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

7. **kwargs uzatmaslik

python
def __init__(self, a):
    super().__init__()                  # ⚠️ boshqa argumentlar yo'qoladi
def __init__(self, a, **kw):
    super().__init__(**kw)              # ✅

8. __init_subclass__ da super() unutish

python
def __init_subclass__(cls, **kw):
    cls.x = 1                           # ⚠️ boshqa mixinlar ishlamaydi
    super().__init_subclass__(**kw)     # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 8.6-dars (o'tilgan): meros asoslari
  • 8.8-dars: MRO va C3 linearizatsiyasi — super() ning asosi
  • 8.9-dars: polimorfizm
  • 8.18-dars: ABC — super().__init_subclass__()
  • 9-qism: maxsus istisnolar — super().__init__(xabar)
  • Django, DRF: mixin arxitekturasi to'liq super() ga tayanadi
  • Maqola: "Python's super() considered super!" — Raymond Hettinger

8. Eng yaxshi amaliyotlar

  1. Argumentsiz super() ishlating. Ota.metod(self) — faqat maxsus holatlarda.

  2. Har __init__ super().__init__() chaqirsin. Hatto ota-sinf object bo'lsa ham.

  3. **kwargs bilan qolganini uzating. Hamkorlikdagi meros shunga tayanadi.

  4. Nomli argumentlar ishlating. Pozitsion tartib MRO da o'zgaradi.

  5. Zanjir oxiridagi sinf noma'lum argumentni aniqlasin. if kw: raise TypeError(...).

  6. Mixinlar super() ni chaqirsin. Zanjir uzilmasin.

  7. Mixin tartibini hujjatlang. Tartib xatti-harakatni o'zgartiradi.

  8. super(type(self), self) yozmang. RecursionError beradi.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
1.  class A:
        def f(self): return "A"
    class B(A):
        def f(self): return "B" + super().f()
    print(B().f())
2.  class A:
        def f(self): return "A"
    class B(A):
        def f(self): return "B" + super().f()
    class C(A):
        def f(self): return "C" + super().f()
    class D(B, C):
        def f(self): return "D" + super().f()
    print(D().f())
3.  class A:
        def __init__(self): self.x = 1
    class B(A):
        def __init__(self): super().__init__(); self.y = 2
    print(sorted(B().__dict__))
4.  class A: pass
    class B(A):
        def f(self): return type(super())
    print(B().f())
5.  class A:
        def f(self): return "A"
    class B(A):
        def f(self): return "B"
    b = B()
    print(super(B, b).f())
6.  class A:
        def f(self): return "A"
    class B(A):
        def f(self): return __class__.__name__
    print(B().f())
7.  class A:
        def f(self): return "A"
    class B(A):
        @staticmethod
        def g():
            try: return super().f()
            except RuntimeError: return "xato"
    print(B.g())
8.  class A:
        def __init__(self, **kw): super().__init__()
    class B(A):
        def __init__(self, b, **kw): super().__init__(**kw); self.b = b
    class C(A):
        def __init__(self, c, **kw): super().__init__(**kw); self.c = c
    class D(B, C):
        def __init__(self, **kw): super().__init__(**kw)
    print(sorted(D(b=1, c=2).__dict__))
9.  class A:
        def f(self): return "A"
    class B(A):
        def f(self): return "B"
    class C(B):
        def f(self): return super(B, self).f()
    print(C().f())
10. class A:
        def f(self): return "A"
    class B(A):
        def f(self): return "B" + super().f()
    class C(B): pass
    print(C().f())
11. class A:
        @classmethod
        def f(cls): return cls.__name__
    class B(A):
        @classmethod
        def f(cls): return "B" + super().f()
    print(B.f())
12. print(super.__doc__.splitlines()[0])
Javoblar
  1. BA
  2. DBCA — B.super() → C
  3. ['x', 'y']
  4. <class 'super'>
  5. A — B dan keyin
  6. B — __class__ yopilmadan
  7. xato — @staticmethod da super() ishlamaydi
  8. ['b', 'c'] — hamkorlikdagi meros
  9. A — B ni o'tkazib yubordi
  10. BA — C da f yo'q
  11. BB — cls = B
  12. super() -> same as super(__class__, <first argument>)

Vazifa 2: Xatolarni tuzating

python
1.  class B(A):
        def __init__(self, x, y):
            self.y = y
2.  class C(A, B):
        def __init__(self):
            A.__init__(self)
            B.__init__(self)
3.  class B(A):
        def f(self): return super(type(self), self).f()
4.  class C(A, B):
        def __init__(self, x, y): super().__init__(x, y)
5.  class Mixin:
        def f(self): return "mixin"
6.  class B(A):
        @staticmethod
        def f(): return super().g()
7.  class B(A):
        def __init__(self, a): super().__init__()
8.  class B(A):
        def __init_subclass__(cls, **kw): cls.x = 1
Javoblar
python
1.  super().__init__(x)  qo'shing
2.  super().__init__()   (va A, B da ham)
3.  super().f()
4.  super().__init__(x=x, y=y, **kw)  va **kw qabul qiling
5.  return "mixin " + super().f()
6.  return super(B, B).g()
7.  def __init__(self, a, **kw): super().__init__(**kw)
8.  super().__init_subclass__(**kw)  qo'shing

Vazifa 3: Mixin to'plami

Yozing:

  1. Asos sinf — bajar(malumot) metodi
  2. ValidatsiyaMixin — kirishni tekshiradi
  3. KeshMixin — natijani keshlaydi
  4. JurnalMixin — yozib boradi
  5. OlchovMixin — vaqtni o'lchaydi
  6. Barchasi hamkorlikdagi __init__ bilan
  7. Turli kombinatsiyalar va tartiblarni sinang

Vazifa 4: super() kuzatuvchisi

Vosita yozing:

  1. Sinf ierarxiyasini olsin
  2. Har metod uchun super() zanjirini ko'rsatsin
  3. Zanjir uzilgan joylarni topsin (super() chaqirmagan sinflar)
  4. Ota.metod(self) ishlatilgan joylarni
  5. super(type(self), self) xatosini
  6. Vizual daraxt chiqarsin

Vazifa 5: Hamkorlikdagi __init__ tekshiruvchisi

  1. Sinf ierarxiyasidagi barcha __init__ ni tekshirsin
  2. super().__init__() chaqirmaganlarni topsin
  3. **kwargs qabul qilmaganlarni
  4. Pozitsion argument uzatayotganlarni
  5. Zanjir oxirida tekshiruv yo'qligini
  6. Tuzatilgan versiyani taklif qilsin

Vazifa 6: Django uslubidagi ko'rinish

  1. Korinish asos sinfi — bajar(sorov)
  2. AutentifikatsiyaMixin — foydalanuvchini tekshiradi
  3. RuxsatMixin — huquqlarni
  4. KeshMixin, JurnalMixin
  5. Har biri super() bilan zanjirga ulanadi
  6. Xato bo'lsa zanjir to'xtasin (403, 401)

Vazifa 7: O'ylash

Nega Python 3 da super() argumentsiz ishlaydi, lekin Python 2 da super(B, self) yozish majburiy edi?

Javob

Chunki argumentsiz super() kompilyator sehri talab qiladi — va Python 2 da sinf jismini kompilyatsiya qilish boshqacha edi.

1. Python 2 dagi holat

python
# Python 2
class B(A):
    def f(self):
        return super(B, self).f()       # ⚠️ ikkalasi ham majburiy

Muammolar:

python
# a) Takrorlanish — sinf nomi ikki marta
class JudaUzunSinfNomi(A):
    def f(self):
        return super(JudaUzunSinfNomi, self).f()    # ⚠️

# b) Sinf nomini o'zgartirsangiz — hamma joyda tuzatish
class YangiNom(A):                      # ⚠️ metodlar ichi eskicha qoldi
    def f(self):
        return super(EskiNom, self).f() # ❌ NameError

# c) Dekorator sinfni almashtirsa
@ozgartir
class B(A):
    def f(self):
        return super(B, self).f()       # ⚠️ B endi boshqa sinf

2. Nega bu qiyin edi

super() ishlashi uchun ikki narsa kerak:

  1. Joriy sinf — MRO da qayerdan boshlashni bilish uchun
  2. Obyekt — self

self ni olish oson (birinchi pozitsion argument). Lekin joriy sinf — muammo:

python
class B(A):
    def f(self):
        # Bu funksiya kompilyatsiya paytida B ni BILMAYDI —
        # B hali yaratilmagan!
        ...

Sinf tanasi bajarilganda B nomi hali mavjud emas (8.2-darsda ko'rgan edik: type() chaqiruvi tananing oxirida bo'ladi).

Ishonchsiz yechimlar:

python
# a) type(self) — ❌ rekursiya
def f(self):
    return super(type(self), self).f()  # avlod bo'lsa cheksiz

# b) self.__class__ — ❌ bir xil muammo

# c) Global qidiruv — ❌ dekorator/qayta nomlashda buziladi
def f(self):
    return super(globals()["B"], self).f()

# d) Frame tekshiruvi — ⚠️ sekin va mo'rt
import sys
def f(self):
    ramka = sys._getframe(1)
    ...

3. Python 3 yechimi — __class__ yopilmasi

PEP 3135 (2007, Calvin Spealman):

Kompilyator metod ichida super() yoki __class__ ni ko'rsa:

  1. Funksiyaga yashirin yopilma o'zgaruvchisi __class__ qo'shadi
  2. Sinf yaratilgandan keyin uni to'ldiradi
python
class B(A):
    def f(self):
        return super().f()

B.f.__code__.co_freevars                # ('__class__',)
B.f.__closure__[0].cell_contents        # <class 'B'>

Ya'ni __class__ — yopilma hujayrasi (cell), sinf yaratilganda to'ldiriladi.

Ko'rsatish:

python
class B(A):
    def f(self):
        print(__class__)                # ⭐ hech qayerda e'lon qilinmagan
        return super().f()

__class__ — Pythonda yagona shunday sehrli o'zgaruvchi.

4. Nega bu Python 2 da qilinmadi

Texnik sabablar:

a) Yopilma mexanizmi cheklangan edi

Python 2 da nonlocal yo'q edi; yopilmalar faqat o'qish uchun ishlardi. __class__ hujayrasini keyinroq to'ldirish murakkabroq.

b) Eski va yangi uslub sinflari

Python 2 da ikki xil sinf bor edi:

python
class Eski:                     # eski uslub (classic)
    pass

class Yangi(object):            # yangi uslub
    pass

super() faqat yangi uslub sinflarda ishlardi. Kompilyator sehri ikkalasini ham qo'llab-quvvatlashi kerak bo'lardi.

python
class Eski:
    def f(self):
        return super(Eski, self).f()    # ❌ TypeError

Python 3 da eski uslub sinflar olib tashlandi — bu yo'lni ochdi.

c) Orqaga moslik

super — o'rnatilgan sinf, funksiya emas:

python
type(super)                     # <class 'type'>
super.__mro__                   # (super, object)

Uni argumentsiz chaqirish mumkin bo'lsa, mavjud kod xatti-harakati o'zgarardi.

5. Amalga oshirish tafsiloti

CPython da super.__init__ argumentsiz chaqirilganda:

c
/* Objects/typeobject.c, super_init_without_args */

/* 1. Joriy freymni ol */
frame = _PyThreadState_GetFrame(tstate);

/* 2. co_varnames[0] — birinchi argument (self/cls) */
obj = _PyFrame_GetLocalsArray(frame)[0];

/* 3. Yopilmadan __class__ ni topish */
for (i = 0; i < co->co_nlocalsplus; i++) {
    if (_PyUnicode_EqualToASCIIId(name, &PyId___class__)) {
        cell = _PyFrame_GetLocalsArray(frame)[i];
        type = (PyTypeObject *) PyCell_GET(cell);
        break;
    }
}

Ya'ni super() freymni tekshiradi — bu Pythonda kamdan-kam uchraydigan sehr.

Oqibatlari:

python
# 1. Freym bo'lmasa — ishlamaydi
lambda: super()                         # ❌

# 2. self birinchi argument bo'lmasa
def f(x, self): super()                 # ⚠️ x ni self deb oladi

# 3. __class__ yopilmada bo'lmasa
exec("super()")                         # ❌ RuntimeError

6. Python 3.12 dagi yaxshilanish

3.12 gacha comprehension ichida super() muammoli edi:

python
class B(A):
    def f(self):
        return [super().g() for _ in range(3)]   # ⚠️ 3.11 da xato

PEP 709 3.12-bob comprehension'larni inline qildi — endi ishlaydi.

7. Boshqa tillar

Til Sintaksis Izoh
Python 3 super().f() Kompilyator sehri
Python 2 super(B, self).f() Qo'lda
Java super.f() Kalit so'z, kompilyator biladi
C++ Asos::f() Aniq sinf nomi
Ruby super Argumentlarni avtomatik uzatadi
JavaScript super.f() Kalit so'z
C# base.f() Kalit so'z

Ruby eng qisqa:

ruby
class B < A
  def f(x, y)
    super              # x va y AVTOMATIK uzatiladi
    super()            # hech narsa uzatilmaydi
    super(x)           # faqat x
  end
end

Python super() ni kalit so'z qilmadi, chunki:

  • Bu — obyekt, uni saqlash/uzatish mumkin
  • Aniq shakl (super(B, self)) hali ham kerak
  • Kalit so'z qo'shish — orqaga moslikni buzadi

8. Nega kalit so'z emas

python
# super() — obyekt, shuning uchun:

s = super()                     # ✅ saqlash mumkin
s.f()
s.g()

class B(A):
    def f(self):
        ota = super()
        return ota.f() + ota.g()    # ✅ ikki marta ishlatish

Java da super — kalit so'z, uni saqlab bo'lmaydi.

Bundan tashqari, super — haqiqiy sinf:

python
super.__mro__                   # (super, object)
isinstance(super(), super)      # metod ichida True

Uni meros olish ham mumkin (juda kamdan-kam):

python
class MeningSuper(super):
    pass

9. Amaliy tavsiyalar

python
# ✅ Odatiy holat
class B(A):
    def f(self):
        return super().f()

# ✅ Aniq shakl kerak bo'lganda
def yamoq(self):
    return super(B, self).f()
B.f = yamoq

# ✅ Statik kontekst
@staticmethod
def g():
    return super(B, B).g()

# ✅ MRO ni sakrash
class C(B):
    def f(self):
        return super(B, self).f()   # B ni o'tkazib yubor

# ❌ Hech qachon
super(type(self), self)             # RecursionError

10. Xulosa

Python 2 → 3 o'tishida super() soddalashtirilishi kichik ko'rinadi, lekin:

  1. Kod takrorlanishini yo'q qildi
  2. Qayta nomlash xatolarini oldini oldi
  3. Dekoratorlar bilan mos ishlaydi
  4. Mixin arxitekturasini soddalashtirdi

Buning narxi — kompilyator sehri (__class__ yopilmasi) va freym tekshiruvi. Bu Pythonning "aniqlik" tamoyiliga to'liq mos kelmaydi, lekin foydasi shu qadar katta ediki, PEP qabul qilindi.

Raymond Hettinger (CPython core dev) buni shunday izohlaydi:

"Argumentsiz super() — Python 3 ning eng kam baholanadigan yaxshilanishlaridan biri. U ko'p merosni amalda ishlatiladigan qildi."

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


Xulosa

Bu darsda super() ning haqiqiy ma'nosini o'rgandik.

Eng muhim uch fikr:

  1. super() ota-sinfni emas, MRO dagi keyingi sinfni qaytaradi. super(B, obj) — type(obj).__mro__ da B dan keyingi sinfdan qidirishni boshlaydigan proxy obyekt. Shuning uchun B.f ichidagi super().f() B() orqali A ga, D(B, C)() orqali esa C ga boradi — bir xil kod, turli natija.

  2. Argumentsiz shakl kompilyator sehriga tayanadi. Metod ichida super() yozilsa, kompilyator funksiyaga yashirin __class__ yopilma o'zgaruvchisini qo'shadi va self ni birinchi pozitsion argumentdan oladi. Shuning uchun u sinf tashqarisida, @staticmethod da va ichki funksiyada ishlamaydi — u yerlarda aniq shakl (super(B, self)) kerak.

  3. Hamkorlikdagi meros to'rt qoidaga tayanadi. Har __init__ super().__init__(**kw) chaqirsin; har sinf o'z argumentini nomli olsin; qolgani **kwargs orqali uzatilsin; zanjir oxiridagi sinf noma'lum argumentni aniqlasin. Ota.__init__(self) esa MRO ni chetlab o'tadi va olmos merosda ota-sinfni ikki marta chaqiradi.

Keyingi darsda MRO ning o'zini ko'ramiz: C3 linearizatsiyasi qanday hisoblanadi, nega ba'zi ierarxiyalar TypeError beradi va ko'p merosni qanday xavfsiz loyihalash mumkin.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
8.7-dars: super() — IlmHamroh