Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Uch daraja
- 2.2. _ — kelishuv
- 2.3. __ — nom buzilishi (name mangling)
- 2.4. Nom buzilishi qoidalari
- 2.5. @property bilan nazorat
- 2.6. Boshqa cheklash usullari
- 2.7. Pythonning falsafasi
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Uch daraja
- Misol 2 — Nom buzilishining haqiqiy maqsadi
- Misol 3 — Haqiqiy kapsulatsiya vositalari
- Misol 4 — Amaliy: kutubxona API si
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
8.10-dars: Kapsulatsiya, _ va __
8-QISM — OBYEKTGA YO'NALTIRILGAN DASTURLASH · 10-dars
1. Kirish va motivatsiya
Pythonda private kalit so'zi yo'q:
class Hisob:
def __init__(self):
self.balans = 1000
self._ichki = "ichki"
self.__sirli = "sirli"
h = Hisob()
h.balans # 1000 ✅ ommaviy
h._ichki # 'ichki' ⚠️ ishlaydi!
h.__sirli # ❌ AttributeError
h._Hisob__sirli # 'sirli' ⚠️ ishlaydi!Uch savol:
- Nega
_ichkiga kirish mumkin? __sirliqayerga g'oyib bo'ldi?- Agar hammasiga kirish mumkin bo'lsa, kapsulatsiya bormi?
Java dasturchi buni ko'rib: "Pythonda kapsulatsiya yo'q" deydi. Bu — noto'g'ri. Python boshqa yondashuvni tanlagan:
"Biz hammamiz kattalarmiz" (we're all consenting adults here)
— Python jamoasining norasmiy shiori
Bu darsda:
-
_— kelishuv, majburlash emas -
__— nom buzilishi (name mangling), yashirish emas - Nom buzilishining haqiqiy maqsadi
@propertybilan nazorat__slots__,__setattr__bilan cheklash- Pythonning kapsulatsiya falsafasi
2. Nazariya — chuqur tushuntirish
2.1. Uch daraja
class A:
ommaviy = 1 # ✅ har kim ishlatishi mumkin
_ichki = 2 # ⚠️ kelishuv: tegmang
__xususiy = 3 # ⚠️ nom buzilishi| Prefiks | Nomi | Ma'nosi | Majburlanadimi |
|---|---|---|---|
nom |
Ommaviy | Ommaviy API | — |
_nom |
Ichki (protected) | "Bu — ichki tafsilot" | Yo'q |
__nom |
Nom buzilishi | Avlodda to'qnashuvni oldini olish | Qisman |
__nom__ |
Dunder | Pythonning maxsus metodlari | — |
2.2. _ — kelishuv
class Ombor:
def __init__(self):
self._malumot = {} # ⚠️ "tegmang"
def saqla(self, k, v):
self._malumot[k] = v # ✅ ichkarida ishlatiladi _ nimani bildiradi:
- "Bu — ichki tafsilot, ommaviy API emas"
- "Kelasi versiyada o'zgarishi mumkin"
- "Ishlatsangiz — o'z javobgarligingizda"
Amaliy ta'siri:
from modul import * # ⭐ _ bilan boshlanadiganlar KELMAYDI
help(obj) # ⚠️ ko'rsatadi
dir(obj) # ⚠️ ko'rsatadi
IDE avtoto'ldirish # odatda yashiradi
linterlar # ogohlantiradiLekin hech narsa to'smaydi:
o = Ombor()
o._malumot["x"] = 1 # ✅ ishlaydi
o._malumot = None # ✅ ishlaydi (obyektni buzadi)2.3. __ — nom buzilishi (name mangling)
class A:
def __init__(self):
self.__x = 1
a = A()
a.__dict__ # {'_A__x': 1} ⭐ nom O'ZGARDIQoida: sinf tanasidagi __nom (ikki pastki chiziq bilan boshlanadi, ko'pi bilan bitta bilan tugaydi) _SinfNomi__nom ga aylanadi.
class Hisob:
def __init__(self):
self.__balans = 0 # → self._Hisob__balans
def olish(self):
return self.__balans # → self._Hisob__balans (avtomatik)Bu — yashirish emas:
h = Hisob()
h.__balans # ❌ AttributeError
h._Hisob__balans # ✅ 0Haqiqiy maqsad — avlodda to'qnashuvni oldini olish:
class Ota:
def __init__(self):
self.__holat = "ota" # _Ota__holat
def ota_metodi(self):
return self.__holat # _Ota__holat
class Bola(Ota):
def __init__(self):
super().__init__()
self.__holat = "bola" # _Bola__holat ⭐ BOSHQA atribut
def bola_metodi(self):
return self.__holat # _Bola__holat
b = Bola()
b.ota_metodi() # 'ota' ✅ buzilmadi
b.bola_metodi() # 'bola'
b.__dict__ # {'_Ota__holat': 'ota', '_Bola__holat': 'bola'}Bir prefikssiz:
class Ota:
def __init__(self): self._holat = "ota"
class Bola(Ota):
def __init__(self):
super().__init__()
self._holat = "bola" # ⚠️ Ota niki YO'Q BO'LDI2.4. Nom buzilishi qoidalari
Qachon amal qiladi:
class A:
__x = 1 # ✅ _A__x
def f(self):
self.__y = 2 # ✅ _A__y
__z = 3 # ✅ lokal — buzilmaydi (funksiyada)Qachon amal qilmaydi:
__nom__ # ❌ dunder — buzilmaydi
__nom_ # ✅ buziladi (bitta _ bilan tugaydi)
__nom__ # ❌ ikki _ bilan tugaydi
_nom # ❌ bitta _
__ # ❌ faqat pastki chiziqlarSinf tashqarisida ishlamaydi:
class A:
def __init__(self): self.__x = 1
a = A()
a.__x # ❌ AttributeError — buzilish yo'qSatr orqali kirish buzilmaydi:
class A:
def f(self):
return getattr(self, "__x") # ⚠️ buzilmaydi → AttributeError
return self.__x # ✅ buziladiMetodlarda ham:
class Ota:
def f(self): return self.__g() # _Ota__g
def __g(self): return "ota"
class Bola(Ota):
def __g(self): return "bola" # _Bola__g — BOSHQA metod
Bola().f() # 'ota' ✅ qayta aniqlanmadiBu — mo'rt asosiy sinf muammosining yechimi (8.6-darsda ko'rgan edik).
2.5. @property bilan nazorat
Kapsulatsiyaning haqiqiy vositasi — nazorat qilingan kirish:
class Harorat:
def __init__(self, selsiy: float = 0):
self._selsiy = 0
self.selsiy = selsiy # setter tekshiradi
@property
def selsiy(self) -> float:
return self._selsiy
@selsiy.setter
def selsiy(self, q: float) -> None:
if q < -273.15:
raise ValueError("Mutlaq noldan past")
self._selsiy = q
@property
def farengeyt(self) -> float: # ⭐ faqat o'qish
return self._selsiy * 9 / 5 + 32Afzalligi — chaqiruvchi kod o'zgarmaydi:
# 1-versiya
class A:
def __init__(self): self.x = 0 # oddiy atribut
# 2-versiya — nazorat qo'shildi
class A:
@property
def x(self): return self._x
@x.setter
def x(self, q):
if q < 0: raise ValueError(...)
self._x = q
a.x = 5 # ✅ ikkalasida ham bir xilShuning uchun Pythonda getter/setter yozilmaydi — kerak bo'lganda @property qo'shiladi.
@property to'liq — 8.15-darsda.
2.6. Boshqa cheklash usullari
A) __slots__ — yangi atribut qo'shishni to'sadi:
class A:
__slots__ = ("x", "y")
a = A()
a.x = 1 # ✅
a.z = 2 # ❌ AttributeErrorB) __setattr__ — har yozishni nazorat qiladi:
class Muzlatilgan:
def __init__(self, x):
object.__setattr__(self, "x", x)
def __setattr__(self, nom, q):
raise AttributeError(f"O'zgarmas: {nom}")C) @dataclass(frozen=True):
@dataclass(frozen=True)
class Nuqta:
x: float
y: float
n = Nuqta(1, 2)
n.x = 5 # ❌ FrozenInstanceErrorD) MappingProxyType — o'zgarmas ko'rinish:
from types import MappingProxyType
class A:
def __init__(self):
self._d = {"a": 1}
@property
def d(self):
return MappingProxyType(self._d) # ✅ o'qish uchun2.7. Pythonning falsafasi
Nega private yo'q:
Amaliy foyda kam. C++/Java da ham
privateni chetlab o'tish mumkin (refleksiya, ko'rsatkichlar).Nosozlikni tuzatish qiyinlashadi. Ichki holatni ko'ra olmaslik — muammo.
Test qilish qiyinlashadi. Ichki metodni to'g'ridan-to'g'ri test qilish kerak bo'lishi mumkin.
Monkey patching mumkin bo'lmaydi. Uchinchi tomon kutubxonasidagi xatoni tuzatib bo'lmaydi.
Ishonch madaniyati. "Hujjatda
_deb yozilgan — demak tegmang" yetarli.
Guido van Rossum:
"Pythonda hamma narsa ochiq. Biz dasturchilarni kattalar deb hisoblaymiz. Agar kimdir ichki API ni ishlatsa — u nima qilayotganini biladi va oqibatini o'z zimmasiga oladi."
Bu javobgarlikni ham anglatadi:
# Kutubxona muallifi:
class Kutubxona:
def _ichki(self): ... # "kelasi versiyada o'zgaradi"
# Foydalanuvchi:
k._ichki() # ⚠️ o'z javobgarligida
# versiya yangilansa buziladi3. Tez ma'lumotnoma
Uch daraja
nom ommaviy API
_nom ichki (kelishuv, majburlanmaydi)
__nom nom buzilishi → _Sinf__nom
__nom__ dunder (Python uchun)Nom buzilishi
class A:
__x = 1 → _A__x
def __g(self): ... → _A__g
Qoidalar:
✅ __nom, __nom_ buziladi
❌ __nom__, _nom, __ buzilmaydi
❌ sinf tashqarisida buzilmaydi
❌ getattr(o, "__x") buzilmaydi
MAQSADI: avlodda nom to'qnashuvini oldini olish
EMAS: yashirish (a._A__x ishlaydi)Nazorat vositalari
@property nazorat qilingan kirish ⭐ asosiy
__slots__ yangi atributni to'sadi
__setattr__ har yozishni ushlaydi
@dataclass(frozen=True) o'zgarmas
MappingProxyType o'qish uchun ko'rinishfrom modul import *
_nom → import qilinmaydi
__all__ → aniq ro'yxat4. Batafsil misollar
Misol 1 — Uch daraja
"""_, __ va ommaviy atributlar."""
print("=== 1. Uch daraja ===\n")
class Namoyish:
"""Uch xil atribut."""
OMMAVIY_KONST = "hamma ishlatishi mumkin"
_ICHKI_KONST = "tegmang"
__XUSUSIY_KONST = "nom buzildi"
def __init__(self):
self.ommaviy = "ommaviy qiymat"
self._ichki = "ichki qiymat"
self.__xususiy = "xususiy qiymat"
def ommaviy_metod(self):
return "ommaviy metod"
def _ichki_metod(self):
return "ichki metod"
def __xususiy_metod(self):
return "xususiy metod"
def hammasini_ol(self):
"""⭐ Ichkarida hammasiga kirish mumkin."""
return {
"ommaviy": self.ommaviy,
"_ichki": self._ichki,
"__xususiy": self.__xususiy, # ⭐ ishlaydi
"__xususiy_metod": self.__xususiy_metod(),
}
n = Namoyish()
print(f" Ichkaridan (hammasi ishlaydi):")
for k, v in n.hammasini_ol().items():
print(f" {k:<18} {v!r}")
print(f"\n Tashqaridan:")
KIRISHLAR = [
("n.ommaviy", lambda: n.ommaviy),
("n._ichki", lambda: n._ichki),
("n.__xususiy", lambda: n.__xususiy),
("n._Namoyish__xususiy", lambda: n._Namoyish__xususiy),
("n.ommaviy_metod()", lambda: n.ommaviy_metod()),
("n._ichki_metod()", lambda: n._ichki_metod()),
("n.__xususiy_metod()", lambda: n.__xususiy_metod()),
("n._Namoyish__xususiy_metod()",
lambda: n._Namoyish__xususiy_metod()),
]
for kod, f in KIRISHLAR:
try:
natija = f"✅ {f()!r}"
except AttributeError as e:
natija = f"❌ AttributeError"
print(f" {kod:<32} {natija}")
print("\n=== ⭐ 2. __dict__ da nima bor ===\n")
print(f" n.__dict__:")
for k, v in n.__dict__.items():
print(f" {k:<24} {v!r}")
print(f"\n ⭐ '__xususiy' YO'Q — u '_Namoyish__xususiy' bo'ldi")
print(f"\n Namoyish.__dict__ dagi atributlar:")
for k in Namoyish.__dict__:
if not k.startswith("__") or k.startswith("_Namoyish"):
print(f" {k}")
print("\n=== 3. Nom buzilishi qoidalari ===\n")
class Qoidalar:
__ikki = "buziladi" # ✅
__ikki_ = "buziladi" # ✅ bitta _ bilan tugaydi
__ikki__ = "buzilmaydi" # ❌ dunder
_bitta = "buzilmaydi" # ❌
__ = "buzilmaydi" # ❌ faqat _
___uch = "buziladi" # ✅ ikkidan ko'p ham
print(f" {'Yozilgan nom':<16} {'__dict__ dagi nom':<26} {'Buzildimi'}")
print(" " + "─" * 56)
NOMLAR = ["__ikki", "__ikki_", "__ikki__", "_bitta", "__", "___uch"]
for nom in NOMLAR:
buzilgan = f"_Qoidalar{nom}"
if buzilgan in Qoidalar.__dict__:
print(f" {nom:<16} {buzilgan:<26} ✅")
elif nom in Qoidalar.__dict__:
print(f" {nom:<16} {nom:<26} ❌")
print(f"""
⭐ QOIDA: ikki (yoki ko'p) _ bilan BOSHLANADI va
ko'pi bilan BITTA _ bilan TUGAYDI → buziladi
""")
print("=== ⚠️ 4. Nom buzilishi ishlamaydigan joylar ===\n")
class Sinov:
def __init__(self):
self.__x = 42
def togri(self):
return self.__x # ✅ buziladi
def getattr_bilan(self):
return getattr(self, "__x") # ⚠️ buzilmaydi
def getattr_togri(self):
return getattr(self, "_Sinov__x") # ✅ qo'lda
def dict_bilan(self):
return self.__dict__.get("__x") # ⚠️ buzilmaydi
def exec_bilan(self):
d = {}
exec("natija = self.__x", {"self": self}, d) # ⚠️
return d.get("natija")
s = Sinov()
USULLAR = ["togri", "getattr_bilan", "getattr_togri", "dict_bilan"]
for u in USULLAR:
try:
natija = f"✅ {getattr(s, u)()!r}"
except AttributeError:
natija = "❌ AttributeError"
print(f" s.{u+'()':<22} {natija}")
try:
s.exec_bilan()
print(f" s.exec_bilan() ⚠️ o'tdi")
except AttributeError:
print(f" s.exec_bilan() ❌ AttributeError (exec da buzilmaydi)")
print(f"""
⭐ Nom buzilishi — KOMPILYATSIYA PAYTIDA, matn darajasida.
Ish vaqtidagi satrlar (getattr, exec, eval) buzilmaydi.
""")
print("=== 5. from modul import * ===\n")
import types
modul = types.ModuleType("sinov_moduli")
exec("""
ommaviy = 1
_ichki = 2
__xususiy = 3
def f(): pass
def _g(): pass
""", modul.__dict__)
import sys
sys.modules["sinov_moduli"] = modul # import uni shu yerdan topadi
nom_fazosi = {}
exec("from sinov_moduli import *", nom_fazosi)
keldi = sorted(k for k in nom_fazosi if not k.startswith("__built"))
print(f" Modulda: ommaviy, _ichki, __xususiy, f, _g")
print(f" import * dan keyin: {keldi}")
print(f"\n ⭐ _ bilan boshlanadiganlar KELMADI")
modul2 = types.ModuleType("sinov2")
exec("""
__all__ = ["ommaviy", "_maxsus"]
ommaviy = 1
_ichki = 2
_maxsus = 3
""", modul2.__dict__)
sys.modules["sinov2"] = modul2
nf2 = {}
exec("from sinov2 import *", nf2)
keldi2 = sorted(k for k in nf2 if not k.startswith("__built"))
print(f"\n __all__ = ['ommaviy', '_maxsus'] bilan:")
print(f" keldi: {keldi2}")
print(f" ⭐ __all__ ustuvor — _maxsus ham keldi")
print("\n=== 6. dir() va help() ===\n")
ommaviy_atr = [a for a in dir(n) if not a.startswith("_")]
ichki_atr = [a for a in dir(n) if a.startswith("_")
and not a.startswith("__")]
buzilgan = [a for a in dir(n) if a.startswith("_Namoyish")]
print(f" Ommaviy: {ommaviy_atr}")
print(f" _ bilan: {[a for a in ichki_atr if not a.startswith('_Namoyish')]}")
print(f" Buzilgan: {buzilgan}")
print(f"""
⚠️ dir() HAMMASINI ko'rsatadi — yashirish yo'q.
⭐ IDE lar odatda _ bilan boshlanadiganlarni
avtoto'ldirishda yashiradi (lekin yoqish mumkin).
""")Natijaning muhim qismi:
=== 1. Uch daraja ===
Tashqaridan:
n.ommaviy ✅ 'ommaviy qiymat'
n._ichki ✅ 'ichki qiymat'
n.__xususiy ❌ AttributeError
n._Namoyish__xususiy ✅ 'xususiy qiymat'
n.__xususiy_metod() ❌ AttributeError
n._Namoyish__xususiy_metod() ✅ 'xususiy metod'
=== ⭐ 2. __dict__ da nima bor ===
n.__dict__:
ommaviy 'ommaviy qiymat'
_ichki 'ichki qiymat'
_Namoyish__xususiy 'xususiy qiymat'
=== 3. Nom buzilishi qoidalari ===
Yozilgan nom __dict__ dagi nom Buzildimi
────────────────────────────────────────────────────────
__ikki _Qoidalar__ikki ✅
__ikki_ _Qoidalar__ikki_ ✅
__ikki__ __ikki__ ❌
_bitta _bitta ❌Nima ko'rsatdi: 2.1, 2.2, 2.3, 2.4-bo'limlar.
Misol 2 — Nom buzilishining haqiqiy maqsadi
"""__ nima uchun kerak — avlodda to'qnashuv."""
print("=== ⚠️ 1. _ bilan to'qnashuv ===\n")
class KeshOta:
"""Ichki kesh ishlatadi."""
def __init__(self):
self._kesh = {} # ⚠️ bitta _
self._urish = 0
def ol(self, k):
if k in self._kesh:
self._urish += 1
return self._kesh[k]
q = f"hisoblangan({k})"
self._kesh[k] = q
return q
def statistika(self):
return {"hajm": len(self._kesh), "urish": self._urish}
class KeshBola(KeshOta):
"""⚠️ Bilmasdan bir xil nom ishlatdi."""
def __init__(self):
super().__init__()
self._kesh = [] # ⚠️ list, dict emas!
self._urish = "yo'q"
def qosh(self, x):
self._kesh.append(x)
b = KeshBola()
b.qosh("a")
b.qosh("b")
print(f" b.qosh('a'); b.qosh('b')")
print(f" b._kesh = {b._kesh}")
print(f"\n Endi ota-sinf metodini chaqiramiz:")
try:
b.ol("kalit")
print(f" b.ol('kalit') → ⚠️ o'tdi")
except (AttributeError, TypeError) as e:
print(f" b.ol('kalit') → ❌ {type(e).__name__}: {e}")
try:
stat = b.statistika()
except TypeError as e:
print(f" b.statistika() → ❌ TypeError: {e}")
else:
print(f" b.statistika() → {stat} ⚠️ xato bermadi, lekin ma'nosiz")
print(f"""
⚠️ MUAMMO: KeshBola muallifi KeshOta ichida _kesh
borligini bilmasdi va uni butunlay buzdi.
""")
print("=== ✅ 2. __ bilan yechim ===\n")
class KeshOtaX:
"""⭐ Xususiy atributlar — nom buzilishi bilan."""
def __init__(self):
self.__kesh = {} # → _KeshOtaX__kesh
self.__urish = 0
def ol(self, k):
if k in self.__kesh:
self.__urish += 1
return self.__kesh[k]
q = f"hisoblangan({k})"
self.__kesh[k] = q
return q
def statistika(self):
return {"hajm": len(self.__kesh), "urish": self.__urish}
class KeshBolaX(KeshOtaX):
"""⭐ Bir xil nom, lekin to'qnashuv YO'Q."""
def __init__(self):
super().__init__()
self.__kesh = [] # → _KeshBolaX__kesh
self.__urish = "yo'q"
def qosh(self, x):
self.__kesh.append(x)
def bola_kesh(self):
return self.__kesh
bx = KeshBolaX()
bx.qosh("a")
bx.qosh("b")
bx.ol("kalit")
bx.ol("kalit")
print(f" bx.qosh('a'); bx.qosh('b'); bx.ol('kalit') × 2\n")
print(f" bx.bola_kesh() = {bx.bola_kesh()}")
print(f" bx.statistika() = {bx.statistika()} ✅ ishladi")
print(f"\n bx.__dict__:")
for k, v in bx.__dict__.items():
print(f" {k:<24} {v!r}")
print(f"\n ⭐ IKKI ALOHIDA atribut — to'qnashuv yo'q")
print("\n=== 3. Metodlar uchun ham ===\n")
class QuvurOta:
"""Shablon metod naqshi."""
def bajar(self, malumot):
"""Ommaviy API — qayta aniqlanmasin."""
malumot = self.__tayyorla(malumot) # _QuvurOta__tayyorla
malumot = self.qayta_ishla(malumot) # ✅ kengaytiriladigan
return self.__yakunla(malumot) # _QuvurOta__yakunla
def __tayyorla(self, m):
"""⭐ Xususiy — avlod tasodifan qayta aniqlay olmaydi."""
return [str(x).strip() for x in m]
def __yakunla(self, m):
return " | ".join(m)
def qayta_ishla(self, m):
"""✅ Kengaytirish nuqtasi."""
return m
class QuvurBola(QuvurOta):
def qayta_ishla(self, m):
return [x.upper() for x in m]
def __tayyorla(self, m):
"""⚠️ Bir xil nom, lekin OTA-SINFNIKI EMAS."""
return ["BUZILGAN"]
def __yakunla(self, m):
return "BUZILGAN"
MALUMOT = [" bir ", " ikki", "uch "]
print(f" Kirish: {MALUMOT}\n")
print(f" QuvurOta().bajar() = {QuvurOta().bajar(MALUMOT)!r}")
print(f" QuvurBola().bajar() = {QuvurBola().bajar(MALUMOT)!r}")
print(f"""
⭐ QuvurBola.__tayyorla va __yakunla CHAQIRILMADI —
ular _QuvurBola__tayyorla, ota-sinf esa
_QuvurOta__tayyorla ni chaqiradi.
Faqat qayta_ishla() (ommaviy) kengaytirildi. ✅
""")
print(f" Metod nomlari:")
for S in (QuvurOta, QuvurBola):
metodlar = [m for m in S.__dict__ if "tayyorla" in m or "yakunla" in m]
print(f" {S.__name__:<12} {metodlar}")
print("\n=== ⚠️ 4. __ ning kamchiliklari ===\n")
class Asos:
def __init__(self):
self.__holat = "boshlang'ich"
def olish(self):
return self.__holat
class Kengaytirilgan(Asos):
def ozgartir(self, q):
"""⚠️ Ota-sinf xususiy atributiga kirish MUMKIN EMAS."""
try:
self.__holat = q # _Kengaytirilgan__holat!
return "⚠️ yangi atribut yaratildi"
except AttributeError as e:
return f"❌ {e}"
k = Kengaytirilgan()
print(f" k.olish() = {k.olish()!r}")
print(f" k.ozgartir('yangi') → {k.ozgartir('yangi')}")
print(f" k.olish() = {k.olish()!r} ⚠️ o'zgarmadi")
print(f" k.__dict__ = {k.__dict__}")
print(f"""
⚠️ __ AVLODLARNI HAM to'sadi — bu ba'zan kerak emas.
✅ Yechim: himoyalangan interfeys bering:
class Asos:
def __init__(self):
self.__holat = "boshlang'ich"
def _holat_orn(self, q): # ⭐ avlodlar uchun
self.__holat = q
""")
class AsosYaxshi:
def __init__(self):
self.__holat = "boshlang'ich"
def olish(self):
return self.__holat
def _holat_orn(self, q):
"""⭐ Avlodlar uchun himoyalangan API."""
if not isinstance(q, str):
raise TypeError("Satr bo'lsin")
self.__holat = q
class KengaytirilganYaxshi(AsosYaxshi):
def ozgartir(self, q):
self._holat_orn(q) # ✅
return "✅ o'zgardi"
ky = KengaytirilganYaxshi()
print(f" ky.olish() = {ky.olish()!r}")
print(f" ky.ozgartir('yangi') → {ky.ozgartir('yangi')}")
print(f" ky.olish() = {ky.olish()!r} ✅")
print("\n=== 5. Qachon __ ishlatish ===\n")
print("""
┌────────────────────────────────┬───────────────────────────┐
│ Holat │ Tavsiya │
├────────────────────────────────┼───────────────────────────┤
│ Kutubxona yozyapsiz │ ⭐ __ (to'qnashuvdan │
│ (boshqalar meros oladi) │ himoya) │
│ Shablon metod ichki qadamlari │ ⭐ __ │
│ Mixin ichki holati │ ⭐ __ (nom to'qnashuvi) │
│ Ichki loyiha, oddiy sinf │ ✅ _ yetadi │
│ Avlodlar ishlatishi kerak │ ✅ _ (protected) │
│ Ommaviy API │ ✅ prefikssiz │
└────────────────────────────────┴───────────────────────────┘
⭐ AMALIY QOIDA:
Sukut bo'yicha _ ishlating.
__ ni faqat AVLODDA TO'QNASHUV xavfi bo'lganda.
⚠️ __ ni "xavfsizlik" uchun ishlatmang — u himoya emas.
""")
print("=== 6. Amaliy: mixin ichki holati ===\n")
class KeshMixin:
"""⭐ __ bilan — boshqa mixinlar bilan to'qnashmaydi."""
def __init__(self, **kw):
super().__init__(**kw)
self.__kesh = {}
self.__urish = 0
def _kesh_ol(self, k):
if k in self.__kesh:
self.__urish += 1
return self.__kesh[k]
return None
def _kesh_qoy(self, k, v):
self.__kesh[k] = v
def kesh_holati(self):
return {"hajm": len(self.__kesh), "urish": self.__urish}
class JurnalMixin:
"""⭐ Ham __kesh ishlatadi — lekin to'qnashuv yo'q."""
def __init__(self, **kw):
super().__init__(**kw)
self.__kesh = [] # _JurnalMixin__kesh
self.__urish = 0
def _yoz(self, x):
self.__kesh.append(x)
self.__urish += 1
def jurnal_holati(self):
return {"yozuvlar": len(self.__kesh), "jami": self.__urish}
class Xizmat(KeshMixin, JurnalMixin):
def __init__(self, **kw):
super().__init__(**kw)
def ishla(self, k):
self._yoz(f"so'rov: {k}")
q = self._kesh_ol(k)
if q is not None:
self._yoz(f"keshdan: {k}")
return q
q = f"natija({k})"
self._kesh_qoy(k, q)
return q
x = Xizmat()
x.ishla("a"); x.ishla("b"); x.ishla("a"); x.ishla("a")
print(f" 4 ta so'rov (2 tasi takroriy):")
print(f" kesh: {x.kesh_holati()}")
print(f" jurnal: {x.jurnal_holati()}")
print(f"\n x.__dict__ kalitlari:")
for k in sorted(x.__dict__):
print(f" {k}")
print(f"""
⭐ Ikkala mixin ham __kesh va __urish ishlatadi,
lekin ular BOSHQA atributlar:
_KeshMixin__kesh
_JurnalMixin__kesh
__ bo'lmasa — ikkinchi mixin birinchisini BUZARDI.
""")Natijaning muhim qismi:
=== ⚠️ 1. _ bilan to'qnashuv ===
b._kesh = ['a', 'b']
b.ol('kalit') → ❌ TypeError: list indices must be integers or slices, not str
b.statistika() → {'hajm': 2, 'urish': "yo'q"} ⚠️ xato bermadi, lekin ma'nosiz
=== ✅ 2. __ bilan yechim ===
bx.bola_kesh() = ['a', 'b']
bx.statistika() = {'hajm': 1, 'urish': 1} ✅ ishladi
bx.__dict__:
_KeshOtaX__kesh {'kalit': 'hisoblangan(kalit)'}
_KeshOtaX__urish 1
_KeshBolaX__kesh ['a', 'b']
_KeshBolaX__urish "yo'q"
=== 3. Metodlar uchun ham ===
QuvurOta().bajar() = 'bir | ikki | uch'
QuvurBola().bajar() = 'BIR | IKKI | UCH'
=== 6. Amaliy: mixin ichki holati ===
x.__dict__ kalitlari:
_JurnalMixin__kesh
_JurnalMixin__urish
_KeshMixin__kesh
_KeshMixin__urishNima ko'rsatdi: 2.3, 2.4-bo'limlar.
Misol 3 — Haqiqiy kapsulatsiya vositalari
"""_ va __ emas, NAZORAT — haqiqiy kapsulatsiya."""
from __future__ import annotations
from dataclasses import dataclass, field, FrozenInstanceError
from types import MappingProxyType
from typing import Any
print("=== 1. @property — nazorat qilingan kirish ===\n")
class Harorat:
"""Fizik chegaralar majburlanadi."""
MUTLAQ_NOL = -273.15
def __init__(self, selsiy: float = 0.0):
self._selsiy = 0.0
self.selsiy = selsiy # ⭐ setter tekshiradi
@property
def selsiy(self) -> float:
return self._selsiy
@selsiy.setter
def selsiy(self, q: float) -> None:
if not isinstance(q, (int, float)) or isinstance(q, bool):
raise TypeError(f"Son bo'lsin: {type(q).__name__}")
if q < self.MUTLAQ_NOL:
raise ValueError(f"Mutlaq noldan past: {q}")
self._selsiy = float(q)
@property
def farengeyt(self) -> float:
"""⭐ Hosila — faqat o'qish."""
return self._selsiy * 9 / 5 + 32
@farengeyt.setter
def farengeyt(self, q: float) -> None:
"""⭐ Teskari hisoblash bilan yozish."""
self.selsiy = (q - 32) * 5 / 9
@property
def kelvin(self) -> float:
return self._selsiy - self.MUTLAQ_NOL
def __repr__(self):
return f"Harorat({self._selsiy:.2f}°C)"
h = Harorat(25)
print(f" {h}")
print(f" farengeyt = {h.farengeyt:.2f}°F")
print(f" kelvin = {h.kelvin:.2f}K")
h.farengeyt = 100
print(f"\n h.farengeyt = 100 → {h}")
print(f"\n Himoya:")
for kod, f in [
("h.selsiy = -300", lambda: setattr(h, "selsiy", -300)),
("h.selsiy = 'issiq'", lambda: setattr(h, "selsiy", "issiq")),
("h.selsiy = True", lambda: setattr(h, "selsiy", True)),
("h.kelvin = 0", lambda: setattr(h, "kelvin", 0)),
("h.farengeyt = -500", lambda: setattr(h, "farengeyt", -500)),
]:
try:
f(); n = "⚠️ O'TDI"
except (ValueError, TypeError, AttributeError) as e:
n = f"✅ {type(e).__name__}: {str(e)[:36]}"
print(f" {kod:<24} {n}")
print(f"\n ⚠️ Lekin _selsiy hali ochiq:")
h._selsiy = -1000
print(f" h._selsiy = -1000 → {h} ⚠️ invariant buzildi")
h._selsiy = 25.0
print(f"""
⭐ @property — asosiy vosita, lekin _ ni to'liq to'smaydi.
To'liq himoya uchun __setattr__ yoki __slots__ kerak.
""")
print("=== 2. __setattr__ — to'liq nazorat ===\n")
class Qatiy:
"""Har yozish tekshiriladi."""
RUXSAT = frozenset({"nom", "yosh", "email"})
TURLAR = {"nom": str, "yosh": int, "email": str}
def __init__(self, nom: str, yosh: int, email: str = ""):
self.nom = nom
self.yosh = yosh
self.email = email
object.__setattr__(self, "_muzlatilgan", True) # ⭐ oxirida
def __setattr__(self, nom: str, q: Any) -> None:
if getattr(self, "_muzlatilgan", False):
raise AttributeError(f"Obyekt muzlatilgan: {nom}")
if nom not in self.RUXSAT and not nom.startswith("_"):
raise AttributeError(
f"Noma'lum atribut: {nom!r}. "
f"Ruxsat: {sorted(self.RUXSAT)}"
)
kutilgan = self.TURLAR.get(nom)
if kutilgan and not isinstance(q, kutilgan):
raise TypeError(
f"{nom}: {kutilgan.__name__} kutildi, "
f"{type(q).__name__} keldi"
)
if nom == "yosh" and not 0 <= q <= 150:
raise ValueError(f"Yosh 0–150: {q}")
object.__setattr__(self, nom, q)
def __delattr__(self, nom: str) -> None:
raise AttributeError(f"O'chirib bo'lmaydi: {nom}")
def __repr__(self):
return f"Qatiy({self.nom!r}, {self.yosh})"
q = Qatiy("Aziz", 30, "aziz@wisar.uz")
print(f" {q}")
print(f"\n Himoya:")
for kod, f in [
("q.nom = 'Yangi'", lambda: setattr(q, "nom", "Yangi")),
("q.yoshi = 40", lambda: setattr(q, "yoshi", 40)),
("del q.nom", lambda: delattr(q, "nom")),
("Qatiy('A', 200)", lambda: Qatiy("A", 200)),
("Qatiy('A', '30')", lambda: Qatiy("A", "30")),
("Qatiy(42, 30)", lambda: Qatiy(42, 30)),
]:
try:
f(); n = "⚠️ O'TDI"
except (AttributeError, TypeError, ValueError) as e:
n = f"✅ {type(e).__name__}: {str(e)[:40]}"
print(f" {kod:<24} {n}")
print("\n=== 3. __slots__ — atributlarni cheklash ===\n")
class Slotli:
__slots__ = ("x", "y", "_ichki")
def __init__(self, x, y):
self.x = x
self.y = y
self._ichki = None
def __repr__(self):
return f"Slotli({self.x}, {self.y})"
s = Slotli(1, 2)
print(f" {s}")
print(f" s.x = {s.x}, s._ichki = {s._ichki}")
print(f"\n Himoya:")
for kod, f in [
("s.x = 10", lambda: setattr(s, "x", 10)),
("s.z = 3", lambda: setattr(s, "z", 3)),
("s.__dict__", lambda: s.__dict__),
]:
try:
natija = f()
n = f"✅ {natija!r}" if natija is not None else "✅ o'tdi"
except AttributeError as e:
n = f"✅ AttributeError: {str(e)[:44]}"
print(f" {kod:<20} {n}")
import tracemalloc
def bayt(yasash, n: int = 20_000) -> int:
"""Bitta obyektning o'rtacha hajmi — tracemalloc bilan (8.19-dars).
⚠️ sys.getsizeof(o.__dict__) Python 3.11+ da lug'atni o'zi yaratib,
natijani oshirib yuboradi — shuning uchun bu usul.
"""
joy = [None] * n
tracemalloc.start()
asos = tracemalloc.get_traced_memory()[0]
for i in range(n):
joy[i] = yasash()
jami = tracemalloc.get_traced_memory()[0] - asos
tracemalloc.stop()
return round(jami / n)
class Oddiy:
def __init__(self, x, y):
self.x = x
self.y = y
self._ichki = None
print(f"\n Xotira (bitta obyekt, 3 atribut):")
print(f" __slots__ bilan: {bayt(lambda: Slotli(1, 2))} bayt")
print(f" __dict__ bilan: {bayt(lambda: Oddiy(1, 2))} bayt")
print("\n=== 4. frozen dataclass ===\n")
@dataclass(frozen=True, slots=True)
class Nuqta:
x: float
y: float
@property
def masofa(self) -> float:
return (self.x ** 2 + self.y ** 2) ** 0.5
def kochir(self, dx: float, dy: float) -> "Nuqta":
"""⭐ Yangi obyekt qaytaradi."""
return Nuqta(self.x + dx, self.y + dy)
n = Nuqta(3, 4)
print(f" {n}, masofa = {n.masofa}")
print(f" n.kochir(1, 1) = {n.kochir(1, 1)}")
print(f" n o'zgarmadi: {n}")
print(f"\n Himoya:")
for kod, f in [
("n.x = 10", lambda: setattr(n, "x", 10)),
("n.z = 1", lambda: setattr(n, "z", 1)),
("del n.x", lambda: delattr(n, "x")),
]:
try:
f(); msg = "⚠️ O'TDI"
except (FrozenInstanceError, AttributeError) as e:
msg = f"✅ {type(e).__name__}"
print(f" {kod:<16} {msg}")
print(f"\n ⭐ Bonus: hashable → to'plam/lug'at kaliti bo'la oladi")
print(f" {{Nuqta(1,2), Nuqta(1,2)}} → "
f"{len({Nuqta(1,2), Nuqta(1,2)})} element")
print("\n=== 5. MappingProxyType — o'qish uchun ko'rinish ===\n")
class Sozlama:
def __init__(self, **kw):
self._d = dict(kw)
@property
def hammasi(self):
"""⭐ O'zgartirib bo'lmaydigan ko'rinish."""
return MappingProxyType(self._d)
def orn(self, k, v):
"""Nazorat qilingan yozish."""
if k.startswith("_"):
raise KeyError(f"Ichki kalit: {k}")
self._d[k] = v
sz = Sozlama(host="localhost", port=8000)
print(f" sz.hammasi = {dict(sz.hammasi)}")
print(f" turi: {type(sz.hammasi).__name__}")
print(f"\n Himoya:")
for kod, f in [
("sz.hammasi['port'] = 1", lambda: sz.hammasi.__setitem__("port", 1)),
("sz.hammasi.clear()", lambda: sz.hammasi.clear()),
("sz.orn('debug', True)", lambda: sz.orn("debug", True)),
("sz.orn('_x', 1)", lambda: sz.orn("_x", 1)),
]:
try:
f(); n = "✅ o'tdi"
except (TypeError, AttributeError, KeyError) as e:
n = f"✅ {type(e).__name__}"
print(f" {kod:<28} {n}")
print(f"\n Oxirgi holat: {dict(sz.hammasi)}")
print(f"""
⚠️ MappingProxyType — KO'RINISH, nusxa emas:
Asl dict o'zgarsa — ko'rinish ham o'zgaradi.
""")
k = sz.hammasi
sz.orn("yangi", 1)
print(f" sz.orn('yangi', 1) dan keyin: {dict(k)}")
print("\n=== 6. Solishtirish ===\n")
print("""
┌──────────────────────┬──────────┬──────────┬───────────────┐
│ Vosita │ Kuchi │ Narxi │ Qachon │
├──────────────────────┼──────────┼──────────┼───────────────┤
│ _ prefiks │ ⚠️ nol │ ✅ yo'q │ Doim (belgi) │
│ __ nom buzilishi │ ⚠️ past │ ✅ yo'q │ Meros xavfi │
│ @property │ ✅ o'rta │ ⚠️ kichik│ Invariant │
│ __slots__ │ ✅ o'rta │ ✅ tejaydi│ Ko'p obyekt │
│ __setattr__ │ ✅ yuqori│ ⚠️ har │ Qat'iy nazorat│
│ │ │ yozishda│ │
│ frozen dataclass │ ✅ yuqori│ ✅ kichik│ O'zgarmas │
│ MappingProxyType │ ✅ o'rta │ ✅ yo'q │ Konteyner │
└──────────────────────┴──────────┴──────────┴───────────────┘
⭐ AMALIY TANLOV:
Ma'lumot obyekti → @dataclass(frozen=True)
Invariant bor → @property + setter
Ko'p obyekt (100k+) → __slots__
Konteyner qaytarish → tuple() / frozenset() / MappingProxyType
Ichki tafsilot belgisi → _ prefiks
Meros to'qnashuvi xavfi → __ prefiks
Umuman o'zgarmasin → __setattr__ yoki frozen
""")Natijaning muhim qismi:
=== 1. @property — nazorat qilingan kirish ===
Harorat(25.00°C)
farengeyt = 77.00°F
Himoya:
h.selsiy = -300 ✅ ValueError: Mutlaq noldan past: -300
h.selsiy = 'issiq' ✅ TypeError: Son bo'lsin: str
h.kelvin = 0 ✅ AttributeError: property 'kelvin' of 'Harorat' objec
⚠️ Lekin _selsiy hali ochiq:
h._selsiy = -1000 → Harorat(-1000.00°C) ⚠️ invariant buzildi
=== 2. __setattr__ — to'liq nazorat ===
q.nom = 'Yangi' ✅ AttributeError: Obyekt muzlatilgan: nom
q.yoshi = 40 ✅ AttributeError: Obyekt muzlatilgan
Qatiy('A', 200) ✅ ValueError: Yosh 0–150: 200
=== 3. __slots__ — atributlarni cheklash ===
s.z = 3 ✅ AttributeError: 'Slotli' object has no
attribute 'z'
Xotira (bitta obyekt, 3 atribut):
__slots__ bilan: 56 bayt
__dict__ bilan: 96 baytNima ko'rsatdi: 2.5, 2.6-bo'limlar.
Misol 4 — Amaliy: kutubxona API si
"""Ommaviy va ichki API ni to'g'ri ajratish."""
from __future__ import annotations
import re
from dataclasses import dataclass, field
from datetime import datetime
from types import MappingProxyType
from typing import Any, Iterator
print("=== VAZIFA BOSHQARUVCHISI ===\n")
__all__ = ["VazifaRoyxati", "Vazifa", "Holat", "VazifaXatosi"]
# ═══ OMMAVIY API ═══
class VazifaXatosi(Exception):
"""Ommaviy istisno."""
class Holat:
"""Vazifa holatlari."""
YANGI = "yangi"
JARAYONDA = "jarayonda"
TUGALLANGAN = "tugallangan"
BEKOR = "bekor"
HAMMASI = frozenset({YANGI, JARAYONDA, TUGALLANGAN, BEKOR})
OTISHLAR = MappingProxyType({
YANGI: frozenset({JARAYONDA, BEKOR}),
JARAYONDA: frozenset({TUGALLANGAN, BEKOR, YANGI}),
TUGALLANGAN: frozenset(),
BEKOR: frozenset({YANGI}),
})
@dataclass
class Vazifa:
"""Bitta vazifa.
OMMAVIY: id, sarlavha, holat, teglar, muddat
ICHKI: _tarix (o'zgarishlar jurnali)
"""
id: int
sarlavha: str
holat: str = Holat.YANGI
muddat: datetime | None = None
_teglar: set[str] = field(default_factory=set, repr=False)
_tarix: list[tuple[datetime, str, str]] = field(
default_factory=list, repr=False
)
def __post_init__(self):
if not self.sarlavha.strip():
raise VazifaXatosi("Sarlavha bo'sh bo'lmasin")
if self.holat not in Holat.HAMMASI:
raise VazifaXatosi(f"Noma'lum holat: {self.holat!r}")
self.sarlavha = self.sarlavha.strip()
self._tarix.append((datetime.now(), "", self.holat))
# ── Ommaviy API ──
@property
def teglar(self) -> frozenset[str]:
"""⭐ O'zgarmas nusxa."""
return frozenset(self._teglar)
@property
def tarix(self) -> tuple[tuple[datetime, str, str], ...]:
return tuple(self._tarix)
@property
def tugallanganmi(self) -> bool:
return self.holat == Holat.TUGALLANGAN
@property
def kechikkanmi(self) -> bool:
if self.muddat is None or self.tugallanganmi:
return False
return datetime.now() > self.muddat
def holat_ozgartir(self, yangi: str) -> None:
"""Holatni o'zgartiradi (o'tish qoidalari bilan)."""
if yangi not in Holat.HAMMASI:
raise VazifaXatosi(f"Noma'lum holat: {yangi!r}")
ruxsat = Holat.OTISHLAR[self.holat]
if yangi not in ruxsat:
raise VazifaXatosi(
f"{self.holat!r} → {yangi!r} mumkin emas. "
f"Ruxsat: {sorted(ruxsat) or 'yakuniy holat'}"
)
self._tarix.append((datetime.now(), self.holat, yangi))
self.holat = yangi
def teg_qosh(self, *teglar: str) -> None:
for t in teglar:
t = self.__teg_normalla(t) # ⭐ xususiy
if t:
self._teglar.add(t)
def teg_ochir(self, teg: str) -> bool:
t = self.__teg_normalla(teg)
if t in self._teglar:
self._teglar.discard(t)
return True
return False
# ── Xususiy (nom buzilishi bilan) ──
@staticmethod
def __teg_normalla(teg: str) -> str:
"""⭐ Ichki normallashtirish qoidasi.
__ bilan — avlod sinf tasodifan qayta aniqlay olmaydi.
"""
return re.sub(r"[^\w-]", "", teg.strip().lower())
class VazifaRoyxati:
"""Vazifalar to'plami.
OMMAVIY API:
qosh, ochir, topish, filtrla, statistika
__len__, __iter__, __contains__, __getitem__
ICHKI (_):
_vazifalar, _keyingi_id
_tekshir — avlodlar qayta aniqlashi mumkin
XUSUSIY (__):
__indeks — ichki tuzilma, avlodlar tegmasin
"""
MAKS_VAZIFA = 1000
def __init__(self, nom: str = "Ro'yxat"):
self.nom = nom # ommaviy
self._vazifalar: dict[int, Vazifa] = {} # ichki
self._keyingi_id = 1
self.__indeks: dict[str, set[int]] = {} # xususiy
self.__ozgarishlar = 0
# ── Ommaviy API ──
def qosh(self, sarlavha: str, **kw) -> Vazifa:
if len(self._vazifalar) >= self.MAKS_VAZIFA:
raise VazifaXatosi(f"Chegara: {self.MAKS_VAZIFA}")
self._tekshir(sarlavha) # ⭐ kengaytiriladigan
v = Vazifa(id=self._keyingi_id, sarlavha=sarlavha, **kw)
self._vazifalar[v.id] = v
self._keyingi_id += 1
self.__indeksga_qosh(v) # ⭐ xususiy
return v
def ochir(self, vazifa_id: int) -> bool:
v = self._vazifalar.pop(vazifa_id, None)
if v is None:
return False
self.__indeksdan_ochir(v)
return True
def topish(self, vazifa_id: int) -> Vazifa:
if vazifa_id not in self._vazifalar:
raise VazifaXatosi(f"Topilmadi: #{vazifa_id}")
return self._vazifalar[vazifa_id]
def filtrla(self, *, holat: str | None = None,
teg: str | None = None,
kechikkan: bool | None = None) -> list[Vazifa]:
natija = list(self._vazifalar.values())
if holat is not None:
natija = [v for v in natija if v.holat == holat]
if teg is not None:
idlar = self.__indeks.get(teg.lower(), set())
natija = [v for v in natija if v.id in idlar]
if kechikkan is not None:
natija = [v for v in natija if v.kechikkanmi == kechikkan]
return natija
def statistika(self) -> dict[str, Any]:
holatlar: dict[str, int] = {}
for v in self._vazifalar.values():
holatlar[v.holat] = holatlar.get(v.holat, 0) + 1
return {
"jami": len(self._vazifalar),
"holatlar": holatlar,
"kechikkan": sum(1 for v in self._vazifalar.values()
if v.kechikkanmi),
"teglar": len(self.__indeks),
"ozgarishlar": self.__ozgarishlar,
}
def teg_qosh(self, vazifa_id: int, *teglar: str) -> None:
v = self.topish(vazifa_id)
self.__indeksdan_ochir(v)
v.teg_qosh(*teglar)
self.__indeksga_qosh(v)
# ── Konteyner protokoli ──
def __len__(self) -> int:
return len(self._vazifalar)
def __iter__(self) -> Iterator[Vazifa]:
return iter(self._vazifalar.values())
def __contains__(self, x) -> bool:
if isinstance(x, Vazifa):
return x.id in self._vazifalar
return x in self._vazifalar
def __getitem__(self, vazifa_id: int) -> Vazifa:
return self.topish(vazifa_id)
def __repr__(self) -> str:
return f"VazifaRoyxati({self.nom!r}, {len(self)} vazifa)"
# ── Himoyalangan (_) — avlodlar kengaytirishi mumkin ──
def _tekshir(self, sarlavha: str) -> None:
"""⭐ Kengaytirish nuqtasi."""
if len(sarlavha) > 200:
raise VazifaXatosi("Sarlavha juda uzun (>200)")
# ── Xususiy (__) — avlodlar TEGMASIN ──
def __indeksga_qosh(self, v: Vazifa) -> None:
for t in v.teglar:
self.__indeks.setdefault(t, set()).add(v.id)
self.__ozgarishlar += 1
def __indeksdan_ochir(self, v: Vazifa) -> None:
for t in v.teglar:
self.__indeks.get(t, set()).discard(v.id)
if not self.__indeks.get(t):
self.__indeks.pop(t, None)
self.__ozgarishlar += 1
print("1. Ommaviy API:\n")
r = VazifaRoyxati("Loyiha")
v1 = r.qosh("Dizaynni tayyorlash")
v2 = r.qosh("Backend yozish", muddat=datetime(2026, 1, 1))
v3 = r.qosh("Testlarni yozish")
r.teg_qosh(v1.id, "dizayn", "UI/UX", " MUHIM ")
r.teg_qosh(v2.id, "backend", "python")
r.teg_qosh(v3.id, "test", "python")
v1.holat_ozgartir(Holat.JARAYONDA)
v1.holat_ozgartir(Holat.TUGALLANGAN)
v2.holat_ozgartir(Holat.JARAYONDA)
print(f" {r}\n")
for v in r:
teglar = ", ".join(sorted(v.teglar)) or "—"
kech = " ⏰" if v.kechikkanmi else ""
print(f" #{v.id} {v.sarlavha:<24} [{v.holat:<12}] {teglar}{kech}")
print(f"\n Statistika: {r.statistika()}")
print("\n\n2. ⭐ Teg normallashtirish (xususiy metod):\n")
print(f" Kiritildi: 'dizayn', 'UI/UX', ' MUHIM '")
print(f" Saqlandi: {sorted(v1.teglar)}")
print(f" ⭐ Vazifa.__teg_normalla ishladi (kichik harf, belgilar olib "
f"tashlandi)")
print("\n\n3. Holat o'tishlari:\n")
print(f" {'Joriy':<14} {'Ruxsat etilgan'}")
print(" " + "─" * 44)
for h, ruxsat in Holat.OTISHLAR.items():
print(f" {h:<14} {sorted(ruxsat) or '(yakuniy)'}")
print(f"\n Sinovlar:")
for kod, f in [
("v1 (tugallangan) → yangi",
lambda: v1.holat_ozgartir(Holat.YANGI)),
("v3 (yangi) → tugallangan",
lambda: v3.holat_ozgartir(Holat.TUGALLANGAN)),
("v3 (yangi) → jarayonda",
lambda: v3.holat_ozgartir(Holat.JARAYONDA)),
("v3 → 'noma`lum'",
lambda: v3.holat_ozgartir("noma'lum")),
]:
try:
f(); n = "✅ o'tdi"
except VazifaXatosi as e:
n = f"✅ VazifaXatosi: {str(e)[:44]}"
print(f" {kod:<28} {n}")
print("\n\n4. ⭐ Kapsulatsiya darajalari:\n")
TEKSHIRUV = [
("r.nom", lambda: r.nom, "ommaviy"),
("r.qosh(...)", lambda: "metod", "ommaviy"),
("len(r)", lambda: len(r), "ommaviy"),
("r[1]", lambda: r[1].sarlavha, "ommaviy"),
("r._vazifalar", lambda: len(r._vazifalar), "ichki (_)"),
("r._tekshir", lambda: "metod", "ichki (_)"),
("r.__indeks", lambda: r.__indeks, "xususiy (__)"),
("r._VazifaRoyxati__indeks",
lambda: len(r._VazifaRoyxati__indeks), "xususiy (__)"),
("v1._teglar", lambda: len(v1._teglar), "ichki (_)"),
("v1.teglar", lambda: len(v1.teglar), "ommaviy"),
]
print(f" {'Kirish':<32} {'Daraja':<14} {'Natija'}")
print(" " + "─" * 62)
for kod, f, daraja in TEKSHIRUV:
try:
natija = f"✅ {f()!r}"
except AttributeError:
natija = "❌ AttributeError"
print(f" {kod:<32} {daraja:<14} {natija}")
print("\n\n5. ⭐ Ichki ma'lumot himoyasi:\n")
for kod, f in [
("v1.teglar.add('yangi')", lambda: v1.teglar.add("yangi")),
("v1.tarix.append(...)", lambda: v1.tarix.append(None)),
("Holat.OTISHLAR['x'] = 1",
lambda: Holat.OTISHLAR.__setitem__("x", 1)),
("Holat.HAMMASI.add('x')", lambda: Holat.HAMMASI.add("x")),
]:
try:
f(); n = "⚠️ O'TDI"
except (AttributeError, TypeError) as e:
n = f"✅ {type(e).__name__}"
print(f" {kod:<32} {n}")
print(f"\n ⚠️ Lekin _ bilan boshlanadiganlar ochiq:")
print(f" v1._teglar.add('buzildi')")
v1._teglar.add("buzildi")
print(f" v1.teglar = {sorted(v1.teglar)} ⚠️ o'zgardi")
v1._teglar.discard("buzildi")
print("\n\n6. Avlod sinf:\n")
class UstuvorRoyxat(VazifaRoyxati):
"""⭐ _tekshir ni kengaytiradi, __indeks ga tegmaydi."""
TAQIQLANGAN = frozenset({"spam", "test123"})
def __init__(self, nom="Ustuvor"):
super().__init__(nom)
self._ustuvorliklar: dict[int, int] = {}
self.__indeks = "⚠️ boshqa atribut" # _UstuvorRoyxat__indeks
def _tekshir(self, sarlavha: str) -> None:
"""⭐ Ota-sinf tekshiruvini kengaytiradi."""
super()._tekshir(sarlavha)
past = sarlavha.lower()
if any(t in past for t in self.TAQIQLANGAN):
raise VazifaXatosi(f"Taqiqlangan so'z: {sarlavha!r}")
def qosh(self, sarlavha, *, ustuvorlik: int = 5, **kw):
v = super().qosh(sarlavha, **kw)
self._ustuvorliklar[v.id] = ustuvorlik
return v
def ustuvor_boyicha(self) -> list[Vazifa]:
return sorted(self, key=lambda v: -self._ustuvorliklar.get(v.id, 0))
u = UstuvorRoyxat()
u.qosh("Muhim vazifa", ustuvorlik=10)
u.qosh("Oddiy vazifa", ustuvorlik=3)
u.qosh("O'rtacha", ustuvorlik=7)
print(f" {u}")
print(f" Ustuvorlik bo'yicha:")
for v in u.ustuvor_boyicha():
print(f" #{v.id} {v.sarlavha:<20} ustuvorlik={u._ustuvorliklar[v.id]}")
print(f"\n Kengaytirilgan tekshiruv:")
try:
u.qosh("Bu spam xabar")
except VazifaXatosi as e:
print(f" u.qosh('Bu spam xabar') → ✅ VazifaXatosi: {e}")
print(f"\n ⭐ __indeks to'qnashuvi YO'Q:")
for k in sorted(k for k in u.__dict__ if "indeks" in k):
print(f" {k}")
print(f"""
⭐ BU LOYIHADA KAPSULATSIYA:
OMMAVIY (prefikssiz):
• qosh, ochir, topish, filtrla, statistika
• __len__, __iter__, __getitem__
• teglar, tarix, tugallanganmi (property)
→ Hujjatlangan, barqaror API
ICHKI (_):
• _vazifalar, _keyingi_id
• _tekshir — ⭐ avlodlar KENGAYTIRISHI mumkin
→ "Ishlatsangiz o'z javobgarligingizda"
XUSUSIY (__):
• __indeks, __ozgarishlar
• __indeksga_qosh, __indeksdan_ochir
• Vazifa.__teg_normalla
→ Avlodlar TASODIFAN buza olmaydi
HIMOYA:
• teglar → frozenset (nusxa)
• tarix → tuple (nusxa)
• Holat.OTISHLAR → MappingProxyType
• Holat.HAMMASI → frozenset
• holat_ozgartir → o'tish qoidalari
__all__ = ["VazifaRoyxati", "Vazifa", "Holat", "VazifaXatosi"]
→ from modul import * faqat shularni beradi
""")Natijaning muhim qismi:
1. Ommaviy API:
VazifaRoyxati('Loyiha', 3 vazifa)
#1 Dizaynni tayyorlash [tugallangan ] dizayn, muhim, uiux
#2 Backend yozish [jarayonda ] backend, python ⏰
#3 Testlarni yozish [yangi ] python, test
3. Holat o'tishlari:
v1 (tugallangan) → yangi ✅ VazifaXatosi: 'tugallangan' → 'yangi'
mumkin emas
v3 (yangi) → tugallangan ✅ VazifaXatosi: 'yangi' → 'tugallangan'
mumkin emas
4. ⭐ Kapsulatsiya darajalari:
Kirish Daraja Natija
──────────────────────────────────────────────────────────────
r._vazifalar ichki (_) ✅ 3
r.__indeks xususiy (__) ❌ AttributeError
r._VazifaRoyxati__indeks xususiy (__) ✅ 6
6. Avlod sinf:
⭐ __indeks to'qnashuvi YO'Q:
_UstuvorRoyxat__indeks
_VazifaRoyxati__indeksNima ko'rsatdi: 2.1, 2.3, 2.5, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
| "Pythonda kapsulatsiya yo'q" | Bor — kelishuv va @property orqali |
"__ atributni yashiradi" |
Nomini o'zgartiradi (_Sinf__nom) |
"__ — xavfsizlik vositasi" |
Faqat to'qnashuvdan himoya |
"_ ga kirish taqiqlangan" |
Kelishuv, texnik cheklov yo'q |
"__ har doim yaxshiroq" |
Avlodlarni ham to'sadi |
| "Getter/setter yozish kerak" | Ochiq atribut → keyin @property |
"__nom__ ham buziladi" |
Dunder buzilmaydi |
"getattr(o, '__x') ishlaydi" |
Satrlar buzilmaydi |
6. Keng tarqalgan xatolar va yechimlari
1. Getter/setter yozish
def get_x(self): return self._x # ⚠️ Java uslubi
self.x = x # ✅ keyin @property2. __ ni "xavfsizlik" uchun
self.__parol = p # ⚠️ o'zgaruvchi himoya emas
# ✅ shifrlang, saqlamang3. Ichki konteynerni qaytarish
@property
def teglar(self): return self._teglar # ⚠️ o'zgartiriladi
def teglar(self): return frozenset(self._teglar) # ✅4. __ avlodlar kerak bo'lganda
self.__holat = q # ⚠️ avlod kira olmaydi
def _holat_orn(self, q): ... # ✅ himoyalangan API5. getattr bilan xususiy atributga kirish
getattr(self, "__x") # ❌ buzilmaydi
getattr(self, "_Sinf__x") # ✅ (lekin nega?)6. __all__ unutish
# modul.py — ⚠️ import * hamma ommaviy nomni beradi
__all__ = ["Asosiy", "yordamchi"] # ✅7. Sinf konstantasi o'zgaruvchan
TURLAR = {"a": 1} # ⚠️ o'zgartiriladi
TURLAR = MappingProxyType({"a": 1}) # ✅8. _ bilan boshlangan @property orqasidagi maydonni ochiq qoldirish
@property
def x(self): return self._x # ⚠️ o._x = ... invariantni buzadi
__slots__ / __setattr__ # ✅ to'liq himoya kerak bo'lsa7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8.3-dars (o'tilgan): invariant va
__init__ - 8.6-dars: mo'rt asosiy sinf —
__bilan yechim - 8.15-dars:
@propertyto'liq - 8.17-dars:
dataclass(frozen=True) - 8.19-dars:
__slots__ - PEP 8: nomlash kelishuvlari
ruff/pylint:_bilan boshlangan a'zolarga kirishni ogohlantiradi
8. Eng yaxshi amaliyotlar
Ochiq atribut yozing, keyin
@propertyqo'shing. Getter/setter — Java uslubi._— sukut tanlov. "Bu ichki tafsilot" degan belgi.__faqat meros to'qnashuvi xavfi bo'lganda. Kutubxona, mixin, shablon metod.Ichki konteynerni nusxa qilib qaytaring.
tuple(),frozenset(),MappingProxyType.Avlodlar uchun
_bilan API bering.__bilan yopilgan holatga kirish yo'li.__all__yozing.import *nima berishini nazorat qiling.Sinf konstantalari o'zgarmas bo'lsin.
frozenset,tuple,MappingProxyType.Kapsulatsiya — hujjat. Nima ommaviy, nima ichki — aniq yozing.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
1. class A:
def __init__(self): self.__x = 1
print(A().__dict__)
2. class A:
def __init__(self): self.__x = 1
a = A()
print(a._A__x)
3. class A:
def __init__(self): self.__x = 1
a = A()
try: a.__x
except AttributeError: print("xato")
4. class A:
__x = 1
__y__ = 2
_z = 3
print([k for k in A.__dict__ if "x" in k or "y" in k or "z" in k])
5. class A:
def __init__(self): self.__x = 1
def f(self): return getattr(self, "__x", "yo'q")
print(A().f())
6. class Ota:
def __init__(self): self.__x = "ota"
class Bola(Ota):
def __init__(self):
super().__init__()
self.__x = "bola"
print(sorted(Bola().__dict__))
7. class A:
def f(self): return self.__g()
def __g(self): return "A"
class B(A):
def __g(self): return "B"
print(B().f())
8. class A:
def __init__(self): self._x = 1
a = A()
a._x = 99
print(a._x)
9. class A:
__slots__ = ("x",)
a = A()
a.x = 1
try: a.y = 2
except AttributeError: print("xato")
10. from dataclasses import dataclass
@dataclass(frozen=True)
class A: x: int
a = A(1)
try: a.x = 2
except Exception as e: print(type(e).__name__)
11. class A:
def __init__(self): self.__x = 1
print(hasattr(A(), "__x"), hasattr(A(), "_A__x"))
12. class A:
___x = 1
print([k for k in A.__dict__ if "x" in k])Javoblar
{'_A__x': 1}1xato['_A__x', '__y__', '_z']— dunder buzilmadiyo'q—getattrsatri buzilmaydi['_Bola__x', '_Ota__x']— ikki alohida atributA—_A__gchaqirildi99—_hech narsani to'smaydixatoFrozenInstanceErrorFalse True['_A___x']— uch_ham buziladi
Vazifa 2: Xatolarni tuzating
1. class A:
def get_x(self): return self._x
def set_x(self, v): self._x = v
2. @property
def teglar(self): return self._teglar # set
3. class A:
TURLAR = {"a": 1}
4. class Asos:
def __init__(self): self.__holat = 1
# avlodlar holatni o'zgartirishi kerak
5. class A:
def f(self): return getattr(self, "__x")
6. # modul.py
class Asosiy: ...
def _yordamchi(): ...
# __all__ yo'q
7. class A:
def __init__(self, parol): self.__parol = parol
8. class A:
@property
def x(self): return self._x
# a._x = -100 invariantni buzadiJavoblar
1. self.x = x (ochiq atribut), kerak bo'lsa @property
2. return frozenset(self._teglar)
3. TURLAR = MappingProxyType({"a": 1})
4. def _holat_orn(self, q): self.__holat = q qo'shing
5. return self.__x (yoki getattr(self, "_A__x"))
6. __all__ = ["Asosiy"]
7. Parolni saqlamang — xesh saqlang (bcrypt)
8. __slots__ yoki __setattr__ bilan _x ni ham himoyalangVazifa 3: Parol sinfi
Yozing:
- Parol hech qachon ochiq saqlanmasin (faqat xesh)
tekshir(parol)— solishtirish__repr__va__str__xeshni ham ko'rsatmasinkuchlilik— property (0-100)- Xeshlash algoritmini almashtirish mumkin bo'lsin
- Serializatsiyada parol chiqmasin
Vazifa 4: Kapsulatsiya tekshiruvchisi
Vosita yozing:
- Sinfning ommaviy/ichki/xususiy a'zolarini ajratsin
_bilan boshlangan a'zolarga tashqi kirishni topsin- Ichki konteynerni qaytaruvchi
@propertylarni - Getter/setter naqshini (Java uslubi)
- O'zgaruvchan sinf konstantalarini
__all__yo'qligini
Vazifa 5: Muzlatilgan konfiguratsiya
- Yaratilgandan keyin o'zgarmasin
- Ichki
dictham himoyalangan bo'lsin bilan(**kw)— yangi nusxa qaytarsin- Sirlar
reprda ko'rinmasin __slots__bilan xotira tejalsin- Barcha himoyalarni test qiling
Vazifa 6: Shablon metod + __
Quvurasos sinfi —bajar()ommaviy- Ichki qadamlar
__bilan - Kengaytirish nuqtalari
_bilan - Uch avlod sinf
- Avlod ichki qadamlarni buza olmasin
- Testlar bilan isbotlang
Vazifa 7: O'ylash
Nega Python private kalit so'zini qo'shmadi, garchi bu ko'p tillarda bo'lsa ham?
Javob
Chunki private ning foydasi kutilganidan kam, narxi esa yuqori — va uni chetlab o'tish har qanday tilda mumkin.
1. private haqiqatan himoya qiladimi?
Java:
class A {
private int x = 42;
}
// Refleksiya bilan:
Field f = A.class.getDeclaredField("x");
f.setAccessible(true); // ⚠️ private o'chirildi
f.get(obj); // 42C++:
class A {
private:
int x = 42;
};
A a;
int* p = (int*)&a; // ⚠️ ko'rsatkich
*p; // 42
// Yoki:
#define private public // ⚠️ ha, bu ishlaydi
#include "A.h"C#:
typeof(A).GetField("x", BindingFlags.NonPublic | BindingFlags.Instance)
.GetValue(obj); // ⚠️ Xulosa: private — kompilyator ogohlantirishi, xavfsizlik chegarasi emas. U tasodifiy xatolardan himoya qiladi, ataylab kirishdan emas.
Python buni ochiq tan oladi: himoya yo'q, faqat kelishuv.
2. private ning haqiqiy narxi
a) Nosozlikni tuzatish qiyinlashadi
# Python — hamma narsa ko'rinadi
>>> obj.__dict__
{'_kesh': {...}, '_holat': 'jarayonda', '_urinishlar': 3}Java da private maydonlarni debuggerdan tashqarida ko'rish uchun refleksiya kerak.
b) Test qilish qiyinlashadi
# Ichki mantiqni to'g'ridan-to'g'ri test qilish
def test_ichki_hisoblash():
o = Hisoblagich()
assert o._xom_hisob(5) == 10 # ✅ Pythonda osonJava da: @VisibleForTesting annotatsiyasi yoki paketni bir xil qilish kerak.
c) Monkey patching mumkin bo'lmaydi
# Uchinchi tomon kutubxonasidagi xatoni vaqtincha tuzatish
import kutubxona
kutubxona.Sinf._buzilgan_metod = mening_tuzatilgan_versiyamBu — haqiqiy amaliyot. Kutubxona muallifi tuzatishni chiqarguncha ishlab turadi.
d) Kengaytirish cheklanadi
class MeningVersiyam(TashqiSinf):
def kengaytir(self):
return self._ichki_holat # ⚠️ Java da: mumkin emas3. Pythonning muqobil yechimi
Kelishuv + hujjat + linterlar:
class Kutubxona:
def ommaviy(self):
"""Barqaror API. Semantik versiyalash amal qiladi."""
def _ichki(self):
"""Ichki. Har versiyada o'zgarishi mumkin.
⚠️ Ishlatsangiz — o'z javobgarligingizda.
"""Bu ishlaydi, chunki:
_— barcha Python dasturchilariga tanish belgi- IDE avtoto'ldirishda yashiradi
- Linterlar ogohlantiradi (
ruff,pylintW0212) from modul import *olmaydi- Kod ko'rib chiqishda darhol ko'rinadi
4. Nom buzilishi — kompromis
__ — private emas, lekin haqiqiy muammoni hal qiladi:
class Kutubxona:
def __init__(self):
self.__holat = {} # _Kutubxona__holat
class Foydalanuvchi(Kutubxona):
def __init__(self):
super().__init__()
self.__holat = [] # _Foydalanuvchi__holat ✅ to'qnashuv yo'qBu — merosdagi tasodifiy to'qnashuv muammosi, ruxsat nazorati emas.
Guido bu haqda:
"Nom buzilishi ruxsat nazorati uchun emas. U — sinf o'z ichki holatini avlodlarning tasodifiy aralashuvidan himoya qilishi uchun."
5. Boshqa tillar bilan solishtirish
| Til | Mexanizm | Chetlab o'tish |
|---|---|---|
| Java | private, protected |
Refleksiya |
| C++ | private, friend |
Ko'rsatkich, #define |
| C# | private, internal |
Refleksiya |
| Ruby | private, protected |
send(:metod) |
| JavaScript | #maydon (ES2022) |
Haqiqatan yopiq |
| Python | _, __ |
To'g'ridan-to'g'ri |
| Go | Katta/kichik harf | Paket chegarasi |
Go eng qiziq:
type A struct {
Ommaviy int // katta harf — eksport qilinadi
ichki int // kichik harf — faqat paket ichida
}Kalit so'z yo'q — nomlash hal qiladi. Python bilan bir xil g'oya, lekin paket darajasida majburlanadi.
JavaScript # — haqiqiy yopiqlik:
class A {
#x = 42; // haqiqatan yopiq
get() { return this.#x; }
}
const a = new A();
a.#x; // ❌ SyntaxError (kompilyatsiya paytida)
Object.keys(a); // []
JSON.stringify(a); // {}Lekin bu ham narx bilan keldi: debugging qiyinlashdi, mavjud vositalar buzildi, dekoratorlar bilan muammo.
6. "Consenting adults" falsafasi
Bu ibora Python jamoasida keng tarqalgan:
"We're all consenting adults here."
Ma'nosi: dasturchilar — kattalar, ular:
- Hujjatni o'qiy oladi
_belgisini tushunadi- Ichki API ni ishlatish oqibatini biladi
- O'z tanlovi uchun javobgar
Bu — ishonch madaniyati, majburlash o'rniga.
Amaliy natija:
# Kutubxona muallifi:
class Kutubxona:
def _ichki(self): ... # "o'zgarishi mumkin"
# Foydalanuvchi:
k._ichki() # ⚠️ ongli qaror
# 2.0 versiyada:
# _ichki() o'chirildi → foydalanuvchi kodi buzildi
# → lekin u OGOHLANTIRILGAN edi7. Amalda bu ishlaydimi?
Ha. Dalillar:
a) Katta kutubxonalar muvaffaqiyatli
requests, django, numpy, pandas — millionlab foydalanuvchi. _ kelishuvi ishlaydi.
b) _ ni buzish — kamdan-kam
Tajribali dasturchilar buni faqat zarurat bo'lganda qiladi va izoh qoldiradi:
# ⚠️ Ichki API — kutubxona #1234 xatosi tufayli
# https://github.com/lib/issues/1234 yopilgach olib tashlanadi
javob._xom_malumotc) Vositalar yordam beradi
ruff check --select SLF # private a'zoga kirish
pylint --enable=W0212 # protected-access8. Qachon Pythonda haqiqiy himoya kerak
Ba'zan kerak — va usullari bor:
# 1. Invariantni majburlash
@property
def yosh(self): return self._yosh
@yosh.setter
def yosh(self, q):
if q < 0: raise ValueError(...)
self._yosh = q
# 2. To'liq o'zgarmaslik
@dataclass(frozen=True, slots=True)
class Nuqta: x: float; y: float
# 3. Atributlarni cheklash
class A:
__slots__ = ("x", "y")
# 4. Har yozishni nazorat qilish
def __setattr__(self, n, q):
if self._muzlatilgan: raise AttributeError(...)
object.__setattr__(self, n, q)
# 5. Konteynerlarni himoyalash
return MappingProxyType(self._d)
return frozenset(self._s)
return tuple(self._l)Muhim: bularning hammasi invariant haqida, ruxsat nazorati haqida emas.
9. Xulosa
Python private ni qo'shmadi, chunki:
- U himoya bermaydi — har tilda chetlab o'tish mumkin
- Narxi bor — debugging, testlash, kengaytirish qiyinlashadi
- Kelishuv yetarli —
_amalda ishlaydi - Falsafaga zid — "consenting adults"
- Muqobillari bor —
@property,frozen,__slots__
Va __ (nom buzilishi) — private emas, balki boshqa muammoning (avlodda nom to'qnashuvi) yechimi.
Umumiy dars: Python "ruxsat nazorati" o'rniga invariant nazoratini tanladi. Muhimi — obyekt noto'g'ri holatga tushmasligi, kim qaysi maydonga tegishi emas.
Nimani mustahkamlaydi: 2.2, 2.3, 2.7-bo'limlar.
Xulosa
Bu darsda kapsulatsiya va Pythonning unga yondashuvini o'rgandik.
Eng muhim uch fikr:
_— kelishuv,__— nom buzilishi; ikkalasi ham himoya emas._nom"bu ichki tafsilot" degan belgi, hech narsani to'smaydi.__nomesa_SinfNomi__nomga aylanadi — bu yashirish emas, avlod sinfda tasodifiy nom to'qnashuvining oldini olish.a._Sinf__nomorqali kirish har doim mumkin.Haqiqiy kapsulatsiya — invariant nazorati.
@propertybilan tekshirilgan kirish,__slots__bilan atribut cheklash,frozen=Truebilan o'zgarmaslik,frozenset/tuple/MappingProxyTypebilan konteyner himoyasi. Muhimi — obyekt noto'g'ri holatga tushmasligi, kim qaysi maydonni ko'rishi emas.Getter/setter yozmang. Ochiq atribut bilan boshlang; nazorat kerak bo'lganda
@propertyqo'shasiz va chaqiruvchi kod o'zgarmaydi. Bu — Pythondaprivateyo'qligining bevosita foydasi: interfeys barqaror qoladi, amalga oshirish erkin o'zgaradi.
Keyingi darsda dunder metodlarga o'tamiz: __str__ va __repr__ — obyektni matn sifatida ko'rsatishning ikki turli maqsadi.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!