Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Nima yaratiladi
- 2.2. Dekorator parametrlari
- 2.3. field()
- 2.4. O'zgaruvchan sukut tuzog'i
- 2.5. __post_init__ va InitVar
- 2.6. Meros va sukut qiymatlar
- 2.7. Yordamchi funksiyalar
- 2.8. Qachon nima
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Nima yaratiladi
- Misol 2 — __post_init__, InitVar, frozen
- Misol 3 — Meros va tuzoqlar
- Misol 4 — Amaliy: konfiguratsiya tizimi
- 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.17-dars: dataclass
8-QISM — OBYEKTGA YO'NALTIRILGAN DASTURLASH · 17-dars
1. Kirish va motivatsiya
Uch atributli oddiy sinf — 25 qator:
class Nuqta:
def __init__(self, x, y, z=0):
self.x, self.y, self.z = x, y, z
def __repr__(self):
return f"Nuqta(x={self.x!r}, y={self.y!r}, z={self.z!r})"
def __eq__(self, b):
if other.__class__ is not self.__class__:
return NotImplemented
return (self.x, self.y, self.z) == (b.x, b.y, b.z)
def __hash__(self):
return hash((self.x, self.y, self.z))
def __lt__(self, b): ...
def __le__(self, b): ...
def __gt__(self, b): ...
def __ge__(self, b): ...dataclass bilan — uch qator:
from dataclasses import dataclass
@dataclass(order=True, frozen=True)
class Nuqta:
x: float
y: float
z: float = 0.0Va bu tuzoqni taqiqlaydi:
@dataclass
class A:
teglar: list = [] # ❌ ValueError yaratish paytida!Bu darsda:
-
@dataclassparametrlari va nima yaratadi field()— har maydonni nozik sozlash__post_init__vaInitVarfrozen,slots,kw_only,order- Meros, sukut qiymatlar tartibi
asdict,astuple,replace,fields- Qachon
dataclass, qachonNamedTuple, qachon oddiy sinf
2. Nazariya — chuqur tushuntirish
2.1. Nima yaratiladi
@dataclass
class Nuqta:
x: float
y: float = 0.0Python quyidagini yozadi:
def __init__(self, x: float, y: float = 0.0) -> None:
self.x = x
self.y = y
def __repr__(self) -> str:
return f"Nuqta(x={self.x!r}, y={self.y!r})"
def __eq__(self, other):
if other.__class__ is self.__class__:
return (self.x, self.y) == (other.x, other.y)
return NotImplementedTur ko'rsatkichi majburiy:
@dataclass
class A:
x: int # ✅ maydon
y = 5 # ⚠️ oddiy sinf atributi, MAYDON EMAS
z: int = 10 # ✅ maydon, sukut bilan y __init__ ga kirmaydi.
typing.ClassVar — ataylab maydon emas:
from typing import ClassVar
@dataclass
class A:
JAMI: ClassVar[int] = 0 # ⭐ sinf atributi, maydon emas
x: int2.2. Dekorator parametrlari
@dataclass(
init=True, # __init__
repr=True, # __repr__
eq=True, # __eq__
order=False, # __lt__, __le__, __gt__, __ge__
unsafe_hash=False, # __hash__ majburan
frozen=False, # o'zgarmas
match_args=True, # __match_args__ (3.10+)
kw_only=False, # barcha maydonlar nomli (3.10+)
slots=False, # __slots__ (3.10+)
weakref_slot=False, # zaif havola sloti (3.11+)
) __hash__ qoidalari:
eq |
frozen |
__hash__ |
|---|---|---|
True (sukut) |
False (sukut) |
None hashable emas |
True |
True |
Avtomatik |
False |
har qanday | object.__hash__ (id bo'yicha) |
unsafe_hash=True |
— | Majburan |
order=True:
@dataclass(order=True)
class A:
x: int
y: int
A(1, 2) < A(1, 3) # True — tuple taqqoslashMaydonlar tartibi taqqoslash tartibini belgilaydi.
2.3. field()
from dataclasses import field
@dataclass
class A:
a: int
b: list = field(default_factory=list) # ⭐ o'zgaruvchan sukut
c: str = field(default="x", repr=False) # repr da yo'q
d: int = field(compare=False, default=0) # taqqoslashda yo'q
e: int = field(init=False, default=0) # __init__ da yo'q
f: dict = field(default_factory=dict,
metadata={"birlik": "kg"}) # metama'lumot
g: int = field(kw_only=True, default=0) # faqat nomli (3.10+)
h: int = field(hash=False, default=0) # __hash__ da yo'q| Parametr | Ma'nosi |
|---|---|
default |
Sukut qiymat |
default_factory |
Har nusxa uchun yangi obyekt |
init |
__init__ ga kirsinmi |
repr |
__repr__ da ko'rinsinmi |
compare |
__eq__/__lt__ da hisobga olinsinmi |
hash |
__hash__ da (sukut: compare qiymati) |
metadata |
Ixtiyoriy metama'lumot (MappingProxyType) |
kw_only |
Faqat nomli argument (3.10+) |
default va default_factory birga bo'lmaydi.
2.4. O'zgaruvchan sukut tuzog'i
@dataclass
class A:
teglar: list = [] # ❌ ValueError!ValueError: mutable default <class 'list'> for field teglar
is not allowed: use default_factory Bu — dataclass ning eng katta afzalligi. Oddiy sinfda:
class A:
def __init__(self, teglar=[]): # ⚠️ jimgina tuzoq
self.teglar = teglarTo'g'ri:
@dataclass
class A:
teglar: list[str] = field(default_factory=list)
sozlama: dict = field(default_factory=dict)
kesh: set = field(default_factory=set)
nuqta: "Nuqta" = field(default_factory=lambda: Nuqta(0, 0)) Tekshiruv __hash__ bo'yicha: tuple, frozenset, str ruxsat; list, dict, set — rad etiladi.
2.5. __post_init__ va InitVar
@dataclass
class Togriturtburchak:
en: float
boy: float
yuza: float = field(init=False) # ⭐ hisoblanadi
def __post_init__(self):
if self.en <= 0 or self.boy <= 0:
raise ValueError("Musbat bo'lsin")
self.yuza = self.en * self.boyInitVar — faqat __init__ uchun:
from dataclasses import InitVar
@dataclass
class Foydalanuvchi:
ism: str
parol: InitVar[str] # ⭐ maydon EMAS
parol_xesh: str = field(init=False, default="")
def __post_init__(self, parol: str): # ⭐ argument sifatida
self.parol_xesh = xesh(parol) InitVar maydonlari __post_init__ ga argument sifatida uzatiladi va obyektda saqlanmaydi.
Tuzoq: InitVar ga standart qiymat berilsa (parol: InitVar[str] = ""), u sinf atributi bo'lib qoladi. Shunda hasattr(obj, "parol") True qaytaradi — lekin bu nusxadagi parol emas, sinfdagi "". Nusxada saqlanmaganini tekshirish uchun "parol" in vars(obj) ishlating.
frozen bilan:
@dataclass(frozen=True)
class A:
x: int
ikki_x: int = field(init=False)
def __post_init__(self):
object.__setattr__(self, "ikki_x", self.x * 2) # ⭐ maxsus2.6. Meros va sukut qiymatlar
@dataclass
class Ota:
a: int
b: int = 0
@dataclass
class Bola(Ota):
c: int # ❌ TypeError!TypeError: non-default argument 'c' follows default argument Sabab: yaratilgan __init__(self, a, b=0, c) — noto'g'ri.
Yechimlar:
# 1. Sukut qiymat berish
@dataclass
class Bola(Ota):
c: int = 0
# 2. kw_only (3.10+)
@dataclass(kw_only=True)
class Ota:
a: int
b: int = 0
@dataclass(kw_only=True)
class Bola(Ota):
c: int # ✅ ishlaydi
# 3. Faqat shu maydon
@dataclass
class Bola(Ota):
c: int = field(kw_only=True)Maydon tartibi merosda:
@dataclass
class Ota:
a: int
b: int = 0
@dataclass
class Bola(Ota):
b: int = 5 # ⭐ qayta aniqlash — TARTIB saqlanadi
c: int = 10
# __init__(self, a, b=5, c=10) — b hali ham ikkinchi2.7. Yordamchi funksiyalar
from dataclasses import (asdict, astuple, replace, fields,
is_dataclass, MISSING)
asdict(obj) # rekursiv lug'at
astuple(obj) # rekursiv tuple
replace(obj, x=5) # ⭐ nusxa + o'zgarish
fields(obj) # Field obyektlari
is_dataclass(obj) # tekshirish asdict — chuqur nusxa:
@dataclass
class A:
lst: list
a = A([1, 2])
d = asdict(a)
d["lst"] is a.lst # False ⭐ nusxa replace — o'zgarmas obyektlar uchun:
@dataclass(frozen=True)
class Sozlama:
host: str
port: int
s = Sozlama("localhost", 8000)
s2 = replace(s, port=443) # ✅ yangi obyekt init=False maydonlarni replace ga uzatib bo'lmaydi.
2.8. Qachon nima
dataclass |
NamedTuple |
TypedDict |
Oddiy sinf | pydantic |
|
|---|---|---|---|---|---|
| O'zgaruvchan | |||||
frozen |
(doim) | qo'lda | |||
| Tur tekshiruvi | qo'lda | ||||
Indeks (x[0]) |
|||||
| Ochish (unpack) | |||||
| Meros | |||||
| Xotira | o'rta | kam | kam | o'rta | ko'p |
| Bog'liqlik |
Tanlash:
NamedTuple— o'zgarmas, tuple kabi, funksiyadan bir necha qiymatdataclass— o'zgaruvchan yokifrozen, metodlar bilanTypedDict— JSON/lug'at strukturasi (obyekt emas)pydantic— tashqi ma'lumot, ish vaqtida tekshiruv- Oddiy sinf — argumentlar maydonlarga mos kelmasa
3. Tez ma'lumotnoma
Asosiy
from dataclasses import dataclass, field
@dataclass(order=True, frozen=True, slots=True, kw_only=True)
class A:
x: int maydon
y: list = field(default_factory=list) ⭐ o'zgaruvchan
z: int = field(init=False, default=0)
JAMI: ClassVar[int] = 0 ⚠️ maydon EMAS
w = 5 ⚠️ maydon EMAS (tur yo'q)Parametrlar
init repr eq sukut True
order __lt__ va boshqalar (eq=True kerak)
frozen o'zgarmas
unsafe_hash __hash__ majburan
slots __slots__ (3.10+)
kw_only barcha maydon nomli (3.10+)
match_args __match_args__ (3.10+)
__hash__: eq=True + frozen=True → avtomatik
eq=True + frozen=False → None ⚠️field()
default sukut qiymat
default_factory ⭐ har nusxaga yangi
init repr compare True/False
hash sukut: compare
metadata dict
kw_only 3.10+Yordamchilar
asdict(o) rekursiv lug'at (chuqur nusxa)
astuple(o) rekursiv tuple
replace(o, x=5) ⭐ nusxa + o'zgarish
fields(o) Field obyektlari
is_dataclass(o) tekshirishMeros
Sukutsiz maydon sukutlidan KEYIN → TypeError
→ kw_only=True yoki sukut bering4. Batafsil misollar
Misol 1 — Nima yaratiladi
"""@dataclass qanday kod yozadi."""
from dataclasses import dataclass, field, fields, asdict, astuple
from typing import ClassVar
import inspect
print("=== 1. Yaratilgan metodlar ===\n")
@dataclass
class Nuqta:
x: float
y: float = 0.0
print(f" @dataclass yaratgan metodlar:")
for m in ["__init__", "__repr__", "__eq__", "__hash__", "__lt__"]:
bor = m in Nuqta.__dict__
q = Nuqta.__dict__.get(m, "—")
print(f" {m:<12} {'✅' if bor else '❌':<4} {q if bor else ''}")
print(f"\n __init__ imzosi:")
print(f" {inspect.signature(Nuqta.__init__)}")
n = Nuqta(3, 4)
print(f"\n Ishlatish:")
print(f" Nuqta(3, 4) → {n!r}")
print(f" Nuqta(3) == Nuqta(3) → {Nuqta(3) == Nuqta(3)}")
print(f" hash(n) → ", end="")
try:
print(hash(n))
except TypeError as e:
print(f"❌ TypeError: {e}")
print("\n\n=== ⚠️ 2. Tur ko'rsatkichi MAJBURIY ===\n")
@dataclass
class Aralash:
maydon: int # ✅ maydon
sukutli: str = "sukut" # ✅ maydon
oddiy = 42 # ⚠️ MAYDON EMAS
KONSTANTA: ClassVar[int] = 100 # ⚠️ ataylab maydon emas
_ichki: bool = True # ✅ maydon
print(f" Sinf tanasidagi nomlar:")
print(f" maydon: int → maydon ✅")
print(f" sukutli: str = ... → maydon ✅")
print(f" oddiy = 42 → ⚠️ oddiy sinf atributi")
print(f" KONSTANTA: ClassVar → ⚠️ ataylab maydon emas")
print(f"\n fields():")
for f in fields(Aralash):
print(f" {f.name:<12} {str(f.type):<24} sukut={f.default!r}")
print(f"\n __init__ imzosi:")
print(f" {inspect.signature(Aralash.__init__)}")
a = Aralash(1)
print(f"\n a = Aralash(1)")
print(f" a.maydon = {a.maydon}")
print(f" a.oddiy = {a.oddiy} ← sinf atributi")
print(f" a.KONSTANTA = {a.KONSTANTA}")
print(f" a.__dict__ = {a.__dict__}")
print(f" ⭐ oddiy va KONSTANTA nusxa lug'atida YO'Q")
print(f"""
⭐ QOIDA: faqat TUR KO'RSATKICHI bor nomlar — maydon.
x: int ✅ maydon
x = 5 ⚠️ oddiy sinf atributi
x: ClassVar[int] = 5 ⚠️ ataylab sinf atributi
""")
print("=== 3. Parametrlar jadvali ===\n")
@dataclass
class Sukut:
x: int = 1
@dataclass(order=True)
class Tartibli:
x: int = 1
@dataclass(frozen=True)
class Muzlatilgan:
x: int = 1
@dataclass(order=True, frozen=True)
class Toliq:
x: int = 1
@dataclass(eq=False)
class EqSiz:
x: int = 1
@dataclass(unsafe_hash=True)
class UnsafeHash:
x: int = 1
@dataclass(repr=False)
class ReprSiz:
x: int = 1
SINFLAR = [Sukut, Tartibli, Muzlatilgan, Toliq, EqSiz, UnsafeHash,
ReprSiz]
ozgarmas = "o'zgarmas"
print(f" {'Sinf':<14} {'repr':<8} {'==':<6} {'<':<6} {'hash':<8} "
f"{ozgarmas}")
print(" " + "─" * 56)
for S in SINFLAR:
a, b = S(), S()
r = "✅" if "__repr__" in S.__dict__ else "❌"
eq = "✅" if a == b else "❌"
try:
a < b; lt = "✅"
except TypeError:
lt = "❌"
try:
hash(a); h = "✅"
except TypeError:
h = "❌"
try:
a.x = 2; muz = "❌"
except Exception:
muz = "✅"
print(f" {S.__name__:<14} {r:<8} {eq:<6} {lt:<6} {h:<8} {muz}")
print(f"""
⭐ __hash__ QOIDALARI:
eq=True, frozen=False → __hash__ = None ⚠️ (sukut)
eq=True, frozen=True → avtomatik ✅
eq=False → object.__hash__ (id)
unsafe_hash=True → majburan yaratiladi
⚠️ SABAB: o'zgaruvchan obyekt hashable bo'lsa —
to'plamda topilmay qoladi (8.12-dars).
""")
print("=== ⭐ 4. field() parametrlari ===\n")
@dataclass
class Toliq2:
# Oddiy maydon
ism: str
# O'zgaruvchan sukut
teglar: list[str] = field(default_factory=list)
# repr da yo'q (sirlar)
parol: str = field(default="", repr=False)
# Taqqoslashda yo'q
yaratilgan: float = field(default=0.0, compare=False)
# __init__ da yo'q — hisoblanadi
uzunlik: int = field(init=False, default=0)
# Metama'lumot
ogirlik: float = field(default=0.0,
metadata={"birlik": "kg", "min": 0})
# Hash da yo'q
kesh: dict = field(default_factory=dict, compare=False,
repr=False)
def __post_init__(self):
self.uzunlik = len(self.ism)
t = Toliq2("Aziz", ["admin"], "maxfiy123", 1234.5, ogirlik=75.5)
print(f" repr: {t!r}")
print(f" ⭐ parol va kesh KO'RINMAYDI\n")
print(f" {'Maydon':<14} {'init':<7} {'repr':<7} {'compare':<9} "
f"{'Qiymat'}")
print(" " + "─" * 62)
for f in fields(Toliq2):
q = getattr(t, f.name)
korinish = repr(q)[:20]
print(f" {f.name:<14} {f.init!s:<7} {f.repr!s:<7} "
f"{f.compare!s:<9} {korinish}")
print(f"\n Metama'lumot:")
for f in fields(Toliq2):
if f.metadata:
print(f" {f.name}: {dict(f.metadata)}")
print(f"\n ⭐ compare=False ta'siri:")
t2 = Toliq2("Aziz", ["admin"], "boshqa", 9999.9, ogirlik=75.5)
print(f" t = Toliq2('Aziz', ..., yaratilgan=1234.5)")
print(f" t2 = Toliq2('Aziz', ..., yaratilgan=9999.9)")
print(f" t == t2 → {t == t2} ⭐ yaratilgan hisobga olinmadi")
print(f" ⚠️ parol taqqoslashda BOR (compare=False emas)")
print("\n\n=== ⭐ 5. O'zgaruvchan sukut tuzog'i ===\n")
print(f" @dataclass ni O'ZI taqiqlaydi:\n")
for tur, nom in [(list, "list"), (dict, "dict"), (set, "set"),
(bytearray, "bytearray")]:
try:
@dataclass
class Xato:
x: tur = tur()
n = "⚠️ o'tdi"
except ValueError as e:
n = f"✅ ValueError: {str(e)[:52]}"
print(f" {nom:<12} = {nom}() → {n}")
print(f"\n O'zgarmas turlar ruxsat:")
for q, nom in [((), "tuple"), (frozenset(), "frozenset"),
("", "str"), (0, "int"), (None, "None")]:
try:
@dataclass
class Ok:
x: type(q) = q
n = "✅ ruxsat"
except ValueError:
n = "❌ rad etildi"
print(f" {nom:<12} = {q!r:<14} → {n}")
print(f"""
⭐ TEKSHIRUV: __hash__ bor-yo'qligi bo'yicha
(dataclasses.py manbasida):
if f.default.__class__.__hash__ is None:
raise ValueError(...)
⭐ TO'G'RI YECHIM:
""")
@dataclass
class Togri:
teglar: list[str] = field(default_factory=list)
sozlama: dict = field(default_factory=dict)
kesh: set = field(default_factory=set)
nuqta: Nuqta = field(default_factory=lambda: Nuqta(0, 0))
a, b = Togri(), Togri()
a.teglar.append("x")
print(f" a.teglar = {a.teglar}")
print(f" b.teglar = {b.teglar} ✅ ajralgan")
print(f" a.nuqta = {a.nuqta}, a.nuqta is b.nuqta = "
f"{a.nuqta is b.nuqta}")
print("\n\n=== 6. Yordamchi funksiyalar ===\n")
@dataclass
class Manzil:
shahar: str
kocha: str
@dataclass
class Odam:
ism: str
manzil: Manzil
teglar: list[str] = field(default_factory=list)
o = Odam("Aziz", Manzil("Toshkent", "Amir Temur"), ["admin", "faol"])
print(f" o = {o!r}\n")
print(f" asdict(o):")
d = asdict(o)
print(f" {d}")
print(f" ⭐ REKURSIV — Manzil ham lug'at bo'ldi")
print(f" d['teglar'] is o.teglar = {d['teglar'] is o.teglar} "
f"⭐ nusxa")
print(f"\n astuple(o):")
print(f" {astuple(o)}")
from dataclasses import replace
print(f"\n replace(o, ism='Malika'):")
o2 = replace(o, ism="Malika")
print(f" {o2!r}")
print(f" o o'zgarmadi: {o.ism!r}")
print(f" ⚠️ manzil BIR obyekt: {o2.manzil is o.manzil}")
print(f"\n fields(o):")
for f in fields(o):
print(f" {f.name:<10} {str(f.type):<18} "
f"factory={f.default_factory is not None}")
from dataclasses import is_dataclass
print(f"\n is_dataclass():")
for x in [o, Odam, Manzil("a", "b"), "matn", 42, dict]:
nom = x.__name__ if isinstance(x, type) else type(x).__name__
print(f" {nom:<12} {is_dataclass(x)}")
print(f"""
⚠️ asdict() CHUQUR nusxa — katta tuzilmalarda sekin.
Faqat sathiy kerak bo'lsa:
{{f.name: getattr(o, f.name) for f in fields(o)}}
""")Natijaning muhim qismi:
=== 1. Yaratilgan metodlar ===
@dataclass yaratgan metodlar:
__init__ ✅ <function Nuqta.__init__ at 0x...>
__repr__ ✅
__eq__ ✅
__hash__ ✅ None
__lt__ ❌
__init__ imzosi:
(self, x: float, y: float = 0.0) -> None
=== ⚠️ 2. Tur ko'rsatkichi MAJBURIY ===
a.__dict__ = {'maydon': 1, 'sukutli': 'sukut', '_ichki': True}
⭐ oddiy va KONSTANTA nusxa lug'atida YO'Q
=== 3. Parametrlar jadvali ===
Sinf repr == < hash o'zgarmas
────────────────────────────────────────────────────────
Sukut ✅ ✅ ❌ ❌ ❌
Toliq ✅ ✅ ✅ ✅ ✅
UnsafeHash ✅ ✅ ❌ ✅ ❌
=== ⭐ 5. O'zgaruvchan sukut tuzog'i ===
list = list() → ✅ ValueError: mutable default <class 'list'> for field x is not alNima ko'rsatdi: 2.1, 2.2, 2.3, 2.4, 2.7-bo'limlar.
Misol 2 — __post_init__, InitVar, frozen
"""Tekshiruv, hisoblanadigan maydonlar va o'zgarmaslik."""
from __future__ import annotations
import hashlib
import math
from dataclasses import (dataclass, field, InitVar, replace,
FrozenInstanceError, asdict)
from datetime import date, datetime
print("=== 1. __post_init__ — tekshiruv ===\n")
@dataclass
class Togriturtburchak:
en: float
boy: float
yuza: float = field(init=False) # ⭐ hisoblanadi
perimetr: float = field(init=False)
kvadratmi: bool = field(init=False, repr=False)
def __post_init__(self):
"""⭐ __init__ dan KEYIN chaqiriladi."""
if self.en <= 0 or self.boy <= 0:
raise ValueError(
f"O'lchamlar musbat bo'lsin: {self.en}×{self.boy}"
)
self.yuza = self.en * self.boy
self.perimetr = 2 * (self.en + self.boy)
self.kvadratmi = math.isclose(self.en, self.boy)
t = Togriturtburchak(3, 4)
print(f" Togriturtburchak(3, 4)")
print(f" {t!r}")
print(f" kvadratmi = {t.kvadratmi}")
print(f"\n Togriturtburchak(5, 5)")
print(f" kvadratmi = {Togriturtburchak(5, 5).kvadratmi}")
print(f"\n Tekshiruv:")
for en, boy in [(0, 5), (-1, 5), (3, 0)]:
try:
Togriturtburchak(en, boy)
n = "⚠️ o'tdi"
except ValueError as e:
n = f"✅ ValueError: {e}"
print(f" ({en}, {boy}) → {n}")
print(f"\n ⚠️ Hisoblangan maydonlar ESKIRADI:")
t.en = 10
print(f" t.en = 10 → yuza = {t.yuza} ⚠️ 12 qoldi (40 bo'lishi kerak)")
print(f"""
✅ YECHIMLAR:
1. frozen=True — o'zgartirib bo'lmaydi
2. @property — har safar hisoblanadi
3. __setattr__ — o'zgarganda qayta hisoblash
""")
@dataclass
class TogriturtburchakYaxshi:
en: float
boy: float
def __post_init__(self):
if self.en <= 0 or self.boy <= 0:
raise ValueError("Musbat bo'lsin")
@property
def yuza(self) -> float:
return self.en * self.boy # ⭐ doim to'g'ri
@property
def perimetr(self) -> float:
return 2 * (self.en + self.boy)
ty = TogriturtburchakYaxshi(3, 4)
print(f" TogriturtburchakYaxshi(3, 4): yuza = {ty.yuza}")
ty.en = 10
print(f" ty.en = 10 → yuza = {ty.yuza} ✅ to'g'ri")
print("\n\n=== ⭐ 2. InitVar ===\n")
def xesh(parol: str, tuz: str = "wisar") -> str:
return hashlib.sha256(f"{tuz}{parol}".encode()).hexdigest()[:16]
@dataclass
class Foydalanuvchi:
ism: str
email: str
parol: InitVar[str] # ⭐ MAYDON EMAS
tuz: InitVar[str] = "wisar" # ⭐ sukut bilan
parol_xesh: str = field(init=False, default="", repr=False)
yaratilgan: datetime = field(default_factory=datetime.now,
repr=False)
def __post_init__(self, parol: str, tuz: str):
"""⭐ InitVar lar ARGUMENT sifatida keladi."""
if len(parol) < 8:
raise ValueError("Parol kamida 8 belgi")
self.parol_xesh = xesh(parol, tuz)
self.email = self.email.lower().strip()
def tekshir(self, parol: str, tuz: str = "wisar") -> bool:
return self.parol_xesh == xesh(parol, tuz)
f = Foydalanuvchi("Aziz", " AZIZ@Wisar.UZ ", "maxfiy123")
print(f" {f!r}\n")
print(f" f.email = {f.email!r} ⭐ normallashtirildi")
print(f" f.parol_xesh = {f.parol_xesh!r}")
print(f"\n ⭐ parol OBYEKTDA SAQLANMAYDI:")
print(f" hasattr(f, 'parol') = {hasattr(f, 'parol')}")
print(f" f.__dict__ kalitlari: {sorted(f.__dict__)}")
print(f"\n Parolni tekshirish:")
for p in ["maxfiy123", "notogri"]:
print(f" f.tekshir({p!r}) = {f.tekshir(p)}")
print(f"\n Tekshiruv:")
try:
Foydalanuvchi("A", "a@b.uz", "qisqa")
except ValueError as e:
print(f" Qisqa parol → ✅ ValueError: {e}")
print(f"\n fields() da InitVar YO'Q:")
from dataclasses import fields as f_fields
print(f" {[x.name for x in f_fields(Foydalanuvchi)]}")
print(f"""
⭐ InitVar ISHLATILISHI:
• Parol → xesh
• Konfiguratsiya → hisoblangan maydonlar
• Fabrika argumenti → obyektda kerak emas
• Tekshiruv rejimi (qat'iy/yumshoq)
""")
print("=== 3. frozen — o'zgarmas ===\n")
@dataclass(frozen=True, slots=True)
class Pul:
miqdor: float
valyuta: str = "UZS"
def __post_init__(self):
"""⚠️ frozen da object.__setattr__ kerak."""
if self.miqdor < 0:
raise ValueError("Manfiy bo'lmasin")
object.__setattr__(self, "valyuta", self.valyuta.upper())
def __add__(self, b):
if not isinstance(b, Pul):
return NotImplemented
if self.valyuta != b.valyuta:
raise ValueError("Valyutalar mos emas")
return Pul(self.miqdor + b.miqdor, self.valyuta)
def __mul__(self, n):
if not isinstance(n, (int, float)):
return NotImplemented
return Pul(self.miqdor * n, self.valyuta)
__rmul__ = __mul__
def __str__(self):
return f"{self.miqdor:,.2f} {self.valyuta}"
p = Pul(1000.50, "uzs")
print(f" Pul(1000.50, 'uzs') = {p!r}")
print(f" valyuta = {p.valyuta!r} ⭐ __post_init__ da katta harf")
print(f" str: {p}")
print(f"\n Himoya:")
for kod, f2 in [
("p.miqdor = 999", lambda: setattr(p, "miqdor", 999)),
("p.valyuta = 'X'", lambda: setattr(p, "valyuta", "X")),
("del p.miqdor", lambda: delattr(p, "miqdor")),
("p.yangi = 1", lambda: setattr(p, "yangi", 1)),
]:
try:
f2(); n = "⚠️ O'TDI"
except (FrozenInstanceError, AttributeError) as e:
n = f"✅ {type(e).__name__}"
print(f" {kod:<20} {n}")
print(f"\n ⭐ Hashable:")
print(f" hash(p) bor: {hash(p) is not None}")
print(f" {{Pul(1), Pul(1), Pul(2)}} → {len({Pul(1), Pul(1), Pul(2)})} element")
print(f"\n Amallar (yangi obyekt):")
print(f" p + Pul(500) = {p + Pul(500)}")
print(f" p * 3 = {p * 3}")
print(f" 3 * p = {3 * p}")
print(f" p o'zgarmadi = {p}")
print(f"\n replace():")
p2 = replace(p, miqdor=2000)
print(f" replace(p, miqdor=2000) = {p2!r}")
print(f" p = {p!r} ✅ o'zgarmadi")
print("\n\n=== ⚠️ 4. frozen va __post_init__ ===\n")
@dataclass(frozen=True)
class Yomon:
x: int
ikki_x: int = field(init=False, default=0)
def __post_init__(self):
self.ikki_x = self.x * 2 # ❌ frozen!
@dataclass(frozen=True)
class Yaxshi:
x: int
ikki_x: int = field(init=False, default=0)
def __post_init__(self):
object.__setattr__(self, "ikki_x", self.x * 2) # ✅
for Sinf in (Yomon, Yaxshi):
try:
o = Sinf(5)
n = f"✅ ikki_x = {o.ikki_x}"
except FrozenInstanceError as e:
n = f"❌ FrozenInstanceError: {e}"
print(f" {Sinf.__name__:<10} {n}")
print(f"""
⭐ frozen da __setattr__ TAQIQLANGAN.
Ichkarida object.__setattr__(self, nom, q) ishlating.
⚠️ Yoki umuman @property qiling:
@property
def ikki_x(self): return self.x * 2 ✅ soddaroq
""")
print("=== 5. slots ===\n")
import sys
@dataclass
class Oddiy:
x: int
y: int
z: int
@dataclass(slots=True)
class Slotli:
x: int
y: int
z: int
def olcham(Sinf, n: int = 20_000) -> int:
"""Bitta nusxaning o'rtacha hajmi — tracemalloc bilan.
⚠️ sys.getsizeof(o.__dict__) Python 3.11+ da lug'atni o'zi yaratib,
natijani oshirib yuboradi (8.19-dars).
"""
import tracemalloc
joy = [None] * n
tracemalloc.start()
asos = tracemalloc.get_traced_memory()[0]
for i in range(n):
joy[i] = Sinf(1, 2, 3)
jami = tracemalloc.get_traced_memory()[0] - asos
tracemalloc.stop()
return round(jami / n)
o1, o2 = Oddiy(1, 2, 3), Slotli(1, 2, 3)
print(f" {'Sinf':<10} {'Bayt':>8} {'100k nusxa':>14} {'__dict__'}")
print(" " + "─" * 48)
for nom, o in [("Oddiy", o1), ("Slotli", o2)]:
n = olcham(type(o))
d = "✅" if hasattr(o, "__dict__") else "❌"
print(f" {nom:<10} {n:>8} {n * 100_000 / 1_048_576:>12.1f} MB {d}")
print(f"\n Yangi atribut:")
for nom, o in [("Oddiy", o1), ("Slotli", o2)]:
try:
o.yangi = 1
n = "⚠️ o'tdi"
except AttributeError:
n = "✅ AttributeError"
print(f" {nom}: o.yangi = 1 → {n}")
print(f"""
⚠️ slots=True CHEKLOVLARI:
• cached_property ishlamaydi (__dict__ yo'q)
• weakref kerak bo'lsa weakref_slot=True (3.11+)
• Ko'p merosda konflikt bo'lishi mumkin
• Dinamik atribut qo'shib bo'lmaydi
""")
print("=== 6. kw_only (3.10+) ===\n")
@dataclass(kw_only=True)
class Sozlama:
"""⭐ Barcha maydonlar NOMLI."""
host: str
port: int
debug: bool = False
try:
Sozlama("localhost", 8000)
except TypeError as e:
print(f" Sozlama('localhost', 8000) → ❌ TypeError")
print(f" {str(e)[:66]}")
s = Sozlama(host="localhost", port=8000)
print(f"\n Sozlama(host='localhost', port=8000) → ✅ {s}")
@dataclass
class Aralash:
"""⭐ Bir qismi pozitsion, bir qismi nomli."""
a: int # pozitsion
b: int = 0 # pozitsion, sukutli
c: int = field(kw_only=True) # ⭐ NOMLI, sukutsiz!
d: int = field(kw_only=True, default=10)
import inspect
print(f"\n Aralash: a, b=0 pozitsion; c, d=10 nomli")
print(f" imzo: {inspect.signature(Aralash.__init__)}")
x = Aralash(1, 2, c=3)
print(f"\n Aralash(1, 2, c=3) = {x}")
try:
Aralash(1, 2, 3)
except TypeError as e:
print(f" Aralash(1, 2, 3) → ❌ TypeError")
print(f"""
⭐ kw_only AFZALLIKLARI:
1. Sukutsiz maydon sukutlidan KEYIN turishi mumkin
2. Chaqiruv o'qiladi: Sozlama(host=..., port=...)
3. Maydon qo'shish/tartibini o'zgartirish xavfsiz
4. Merosdagi tartib muammosi yo'q
""")Natijaning muhim qismi:
=== 1. __post_init__ — tekshiruv ===
Togriturtburchak(3, 4)
Togriturtburchak(en=3, boy=4, yuza=12, perimetr=14)
⚠️ Hisoblangan maydonlar ESKIRADI:
t.en = 10 → yuza = 12 ⚠️ 12 qoldi (40 bo'lishi kerak)
TogriturtburchakYaxshi(3, 4): yuza = 12
ty.en = 10 → yuza = 40 ✅ to'g'ri
=== ⭐ 2. InitVar ===
⭐ parol OBYEKTDA SAQLANMAYDI:
hasattr(f, 'parol') = False
f.__dict__ kalitlari: ['email', 'ism', 'parol_xesh', 'yaratilgan']
=== ⚠️ 4. frozen va __post_init__ ===
Yomon ❌ FrozenInstanceError: cannot assign to field 'ikki_x'
Yaxshi ✅ ikki_x = 10
=== 5. slots ===
Sinf Bayt 100k nusxa __dict__
────────────────────────────────────────────────
Oddiy 96 9.2 MB ✅
Slotli 56 5.3 MB ❌Nima ko'rsatdi: 2.2, 2.5-bo'limlar.
Misol 3 — Meros va tuzoqlar
"""dataclass merosidagi nozikliklar."""
from dataclasses import dataclass, field, fields, replace
from typing import ClassVar
import inspect
print("=== ⚠️ 1. Sukut qiymatlar tartibi ===\n")
@dataclass
class Ota:
a: int
b: int = 0
print(f" @dataclass class Ota: a: int; b: int = 0")
print(f" __init__: {inspect.signature(Ota.__init__)}\n")
print(f" Avlodda SUKUTSIZ maydon:")
try:
@dataclass
class BolaYomon(Ota):
c: int # ❌
print(f" ⚠️ o'tdi")
except TypeError as e:
print(f" ❌ TypeError: {e}")
print(f"""
⭐ SABAB: yaratiladigan __init__ bo'lardi:
def __init__(self, a, b=0, c): ❌ sintaksis xatosi
""")
print(f" ✅ YECHIM 1 — sukut qiymat:")
@dataclass
class Bola1(Ota):
c: int = 0
print(f" {inspect.signature(Bola1.__init__)}")
print(f"\n ✅ YECHIM 2 — kw_only (3.10+):")
@dataclass(kw_only=True)
class OtaKw:
a: int
b: int = 0
@dataclass(kw_only=True)
class BolaKw(OtaKw):
c: int # ✅ ishlaydi
print(f" {inspect.signature(BolaKw.__init__)}")
print(f" BolaKw(a=1, c=3) = {BolaKw(a=1, c=3)}")
print(f"\n ✅ YECHIM 3 — faqat shu maydon kw_only:")
@dataclass
class Bola3(Ota):
c: int = field(kw_only=True)
print(f" {inspect.signature(Bola3.__init__)}")
print(f" Bola3(1, 2, c=3) = {Bola3(1, 2, c=3)}")
print("\n\n=== 2. Maydon tartibi merosda ===\n")
@dataclass
class Asos:
a: int
b: str = "asos-b"
c: float = 0.0
@dataclass
class Avlod(Asos):
b: str = "avlod-b" # ⭐ qayta aniqlash
d: bool = True # yangi
print(f" Asos: a, b='asos-b', c=0.0")
print(f" Avlod: b='avlod-b' (qayta), d=True (yangi)\n")
print(f" Asos.__init__: {inspect.signature(Asos.__init__)}")
print(f" Avlod.__init__: {inspect.signature(Avlod.__init__)}")
print(f"\n ⭐ b HALI HAM ikkinchi o'rinda — tartib SAQLANADI")
print(f" (faqat sukut qiymati o'zgardi)")
print(f"\n fields(Avlod):")
for f in fields(Avlod):
print(f" {f.name:<6} {str(f.type):<10} sukut={f.default!r}")
print(f"\n Avlod(1) = {Avlod(1)}")
print("\n\n=== ⚠️ 3. eq va hash merosda ===\n")
@dataclass
class OtaEq:
x: int
@dataclass
class BolaEq(OtaEq):
y: int = 0
a, b = OtaEq(1), BolaEq(1, 0)
print(f" OtaEq(1) == BolaEq(1, 0) → {a == b}")
print(f" ⭐ SABAB: __eq__ da other.__class__ is self.__class__")
print(f" Turli sinflar → NotImplemented → False")
print(f"\n Yaratilgan __eq__ mantiqi:")
print(f"""
def __eq__(self, other):
if other.__class__ is self.__class__: ⭐ ANIQ tur
return (self.x,) == (other.x,)
return NotImplemented
""")
@dataclass(frozen=True)
class OtaFrozen:
x: int
try:
@dataclass
class BolaOzgaruvchan(OtaFrozen):
y: int = 0
except TypeError as e:
print(f" frozen Ota → o'zgaruvchan Bola:")
print(f" ❌ TypeError: {e}")
try:
@dataclass(frozen=True)
class BolaFrozen(OtaFrozen):
y: int = 0
print(f"\n frozen Ota → frozen Bola: ✅ ishlaydi")
print(f" BolaFrozen(1, 2) = {BolaFrozen(1, 2)}")
except TypeError as e:
print(f" ❌ {e}")
print(f"""
⭐ QOIDA: frozen ierarxiya bo'ylab BIR XIL bo'lishi kerak.
frozen → frozen ✅
oddiy → oddiy ✅
frozen → oddiy ❌
oddiy → frozen ❌
""")
print("=== ⚠️ 4. ClassVar va meros ===\n")
@dataclass
class Hisoblagich:
JAMI: ClassVar[int] = 0 # ⭐ maydon EMAS
_KESH: ClassVar[dict] = {} # ⭐ o'zgaruvchan, lekin OK
nom: str
def __post_init__(self):
Hisoblagich.JAMI += 1
Hisoblagich._KESH[self.nom] = self
h1, h2, h3 = Hisoblagich("a"), Hisoblagich("b"), Hisoblagich("c")
print(f" fields(): {[f.name for f in fields(Hisoblagich)]}")
print(f" ⭐ JAMI va _KESH YO'Q (ClassVar)")
print(f"\n Hisoblagich.JAMI = {Hisoblagich.JAMI}")
print(f" Kesh: {sorted(Hisoblagich._KESH)}")
print(f" h1.__dict__ = {h1.__dict__}")
print(f"\n ⭐ ClassVar o'zgaruvchan bo'lishi MUMKIN:")
print(f" _KESH: ClassVar[dict] = {{}} ✅ ruxsat")
print(f" kesh: dict = {{}} ❌ ValueError")
try:
@dataclass
class Xato:
kesh: dict = {}
except ValueError as e:
print(f"\n Tasdiqlash: ❌ ValueError: {str(e)[:50]}")
print("\n\n=== 5. Metodlar va meros ===\n")
@dataclass
class Shakl:
nom: str
def yuza(self) -> float:
raise NotImplementedError
def tavsif(self) -> str:
"""⭐ Meros olinadi."""
return f"{self.nom}: yuza={self.yuza():.2f}"
@classmethod
def turlar(cls) -> list[str]:
return [S.__name__ for S in cls.__subclasses__()]
@dataclass
class Doira(Shakl):
radius: float = 1.0
def yuza(self) -> float:
return 3.14159 * self.radius ** 2
@dataclass
class Kvadrat(Shakl):
tomon: float = 1.0
def yuza(self) -> float:
return self.tomon ** 2
@dataclass
class Togriturtburchak(Shakl):
en: float = 1.0
boy: float = 1.0
def yuza(self) -> float:
return self.en * self.boy
SHAKLLAR = [Doira("Doira", 5), Kvadrat("Kvadrat", 4),
Togriturtburchak("To'rtburchak", 3, 6)]
print(f" Shakl turlari: {Shakl.turlar()}\n")
for s in SHAKLLAR:
print(f" {s.tavsif()}")
print(f" repr: {s!r}")
print(f"\n Jami yuza: {sum(s.yuza() for s in SHAKLLAR):.2f}")
print(f"""
⭐ dataclass METODLARNI to'sMAYDI:
• Oddiy metodlar ✅
• @property ✅
• @classmethod, @staticmethod ✅
• Dunder metodlar (agar dataclass yaratmasa) ✅
""")
print("=== ⚠️ 6. property bilan tuzoq ===\n")
print(""" ⚠️ MUAMMO: dataclass va property nomlari to'qnashadi
@dataclass
class A:
x: int
@property
def x(self): return self._x # ⚠️ maydon to'sildi
⭐ SABAB: @property sinf atributi bo'lib qoladi,
dataclass uni MAYDON SUKUTI deb hisoblaydi.
""")
@dataclass
class Muammoli:
x: int = 0
@property
def x(self): # ⚠️
return self._x
@x.setter
def x(self, q):
self._x = q
try:
m = Muammoli(5)
print(f" Muammoli(5).x = {m.x}")
m2 = Muammoli()
print(f" Muammoli().x = {m2.x!r} ⚠️ property obyekti!")
except Exception as e:
print(f" ❌ {type(e).__name__}: {e}")
print(f"\n ✅ YECHIM 1 — boshqa nom:")
@dataclass
class Yechim1:
_x: int = 0
@property
def x(self) -> int:
return self._x
@x.setter
def x(self, q: int) -> None:
if q < 0:
raise ValueError("Manfiy bo'lmasin")
self._x = q
y1 = Yechim1(5)
print(f" Yechim1(5).x = {y1.x}")
y1.x = 10
print(f" y1.x = 10 → {y1.x}, y1._x = {y1._x}")
try:
y1.x = -1
except ValueError as e:
print(f" y1.x = -1 → ✅ ValueError: {e}")
print(f"\n ✅ YECHIM 2 — __post_init__ da tekshirish:")
@dataclass
class Yechim2:
x: int = 0
def __post_init__(self):
if self.x < 0:
raise ValueError("Manfiy bo'lmasin")
print(f" Yechim2(5) = {Yechim2(5)}")
try:
Yechim2(-1)
except ValueError as e:
print(f" Yechim2(-1) → ✅ ValueError: {e}")
print(f" ⚠️ Lekin y.x = -1 keyin o'tadi")
print(f"\n ✅ YECHIM 3 — deskriptor (8.15-dars):")
class Musbat:
def __set_name__(self, ega, nom):
self.nom = f"_{nom}"
def __get__(self, obj, ega=None):
if obj is None: return self
return getattr(obj, self.nom, 0)
def __set__(self, obj, q):
if q < 0:
raise ValueError(f"{self.nom[1:]} manfiy bo'lmasin")
setattr(obj, self.nom, q)
@dataclass
class Yechim3:
x: int = Musbat() # ⭐ deskriptor sukut
y3 = Yechim3(5)
print(f" Yechim3(5).x = {y3.x}")
try:
y3.x = -1
except ValueError as e:
print(f" y3.x = -1 → ✅ ValueError: {e}")
print(f"""
⭐ Deskriptor + dataclass:
Python 3.11+ da deskriptor sukut sifatida ishlaydi.
__set_name__ chaqiriladi, tekshiruv har yozishda.
""")Natijaning muhim qismi:
=== ⚠️ 1. Sukut qiymatlar tartibi ===
Avlodda SUKUTSIZ maydon:
❌ TypeError: non-default argument 'c' follows default argument
✅ YECHIM 2 — kw_only (3.10+):
(self, *, a: int, b: int = 0, c: int) -> None
=== 2. Maydon tartibi merosda ===
Asos.__init__: (self, a: int, b: str = 'asos-b', c: float = 0.0)
Avlod.__init__: (self, a: int, b: str = 'avlod-b', c: float = 0.0,
d: bool = True)
⭐ b HALI HAM ikkinchi o'rinda — tartib SAQLANADI
=== ⚠️ 3. eq va hash merosda ===
OtaEq(1) == BolaEq(1, 0) → False
frozen Ota → o'zgaruvchan Bola:
❌ TypeError: cannot inherit non-frozen dataclass from a frozen one
=== ⚠️ 6. property bilan tuzoq ===
Muammoli().x = <property object at 0x...> ⚠️ property obyekti!Nima ko'rsatdi: 2.6-bo'lim.
Misol 4 — Amaliy: konfiguratsiya tizimi
"""dataclass ning barcha imkoniyatlari bir loyihada."""
from __future__ import annotations
import json
import os
import re
from dataclasses import (dataclass, field, fields, asdict, replace,
InitVar, MISSING)
from datetime import datetime, timedelta
from enum import Enum
from pathlib import Path
from typing import Any, ClassVar
print("=== KONFIGURATSIYA TIZIMI ===\n")
class Muhit(str, Enum):
ISHLAB_CHIQISH = "ishlab_chiqish"
SINOV = "sinov"
ISHLAB_CHIQARISH = "ishlab_chiqarish"
def __str__(self): return self.value
@dataclass(frozen=True, slots=True, order=True)
class Versiya:
"""⭐ frozen + slots + order — barchasi bepul."""
katta: int
kichik: int = 0
tuzatish: int = 0
@classmethod
def parse(cls, s: str) -> "Versiya":
m = re.match(r"^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?$", s.strip())
if not m:
raise ValueError(f"Noto'g'ri versiya: {s!r}")
return cls(*(int(q) if q else 0 for q in m.groups()))
def __str__(self):
return f"{self.katta}.{self.kichik}.{self.tuzatish}"
@dataclass(frozen=True, slots=True)
class Manzil:
"""Ulanish manzili."""
host: str = "localhost"
port: int = 8000
ssl: bool = False
def __post_init__(self):
if not 1 <= self.port <= 65535:
raise ValueError(f"Port 1–65535: {self.port}")
if not self.host.strip():
raise ValueError("Host bo'sh bo'lmasin")
object.__setattr__(self, "host", self.host.strip().lower())
@property
def url(self) -> str:
sxema = "https" if self.ssl else "http"
port = "" if self.port in (80, 443) else f":{self.port}"
return f"{sxema}://{self.host}{port}"
@classmethod
def parse(cls, s: str) -> "Manzil":
m = re.match(r"^(?:(https?)://)?([^:/]+)(?::(\d+))?", s.strip())
if not m:
raise ValueError(f"Noto'g'ri manzil: {s!r}")
sxema, host, port = m.groups()
ssl = sxema == "https"
return cls(host, int(port) if port else (443 if ssl else 80), ssl)
def __str__(self): return self.url
@dataclass(kw_only=True)
class BazaSozlama:
"""⭐ kw_only — barcha maydon nomli."""
manzil: Manzil = field(default_factory=lambda: Manzil("localhost", 5432))
baza: str = "wisar"
foydalanuvchi: str = "postgres"
parol: InitVar[str] = "" # ⭐ saqlanmaydi
_parol_bor: bool = field(init=False, default=False, repr=False)
hovuz_hajmi: int = 10
vaqt_chegarasi: float = 30.0
# ⭐ Ichki holat
_ulanish_url: str = field(init=False, default="", repr=False)
def __post_init__(self, parol: str):
if self.hovuz_hajmi < 1:
raise ValueError(f"hovuz_hajmi >= 1: {self.hovuz_hajmi}")
self._parol_bor = bool(parol)
yashirin = "***" if parol else ""
self._ulanish_url = (
f"postgresql://{self.foydalanuvchi}:{yashirin}"
f"@{self.manzil.host}:{self.manzil.port}/{self.baza}"
)
@property
def ulanish_url(self) -> str:
return self._ulanish_url
@dataclass(kw_only=True)
class Sozlama:
"""Asosiy konfiguratsiya."""
# ⭐ ClassVar — maydon emas
VERSIYA: ClassVar[Versiya] = Versiya(2, 1, 0)
_NUSXALAR: ClassVar[int] = 0
# Majburiy
nom: str
# Sukutli
muhit: Muhit = Muhit.ISHLAB_CHIQISH
manzil: Manzil = field(default_factory=Manzil)
baza: BazaSozlama = field(default_factory=BazaSozlama)
# O'zgaruvchan — default_factory
ruxsat_etilgan: list[str] = field(default_factory=lambda: ["*"])
xususiyatlar: dict[str, bool] = field(default_factory=dict)
teglar: set[str] = field(default_factory=set)
# Sirlar — repr da yo'q
api_kalit: str = field(default="", repr=False)
# Taqqoslashda yo'q
yaratilgan: datetime = field(default_factory=datetime.now,
compare=False, repr=False)
# Hisoblanadi
debug: bool = field(init=False, default=False)
_id: int = field(init=False, default=0, compare=False, repr=False)
def __post_init__(self):
if not self.nom.strip():
raise ValueError("Nom bo'sh bo'lmasin")
self.nom = self.nom.strip()
if isinstance(self.muhit, str):
self.muhit = Muhit(self.muhit)
# ⭐ Bog'liq qiymat
self.debug = self.muhit != Muhit.ISHLAB_CHIQARISH
if self.muhit == Muhit.ISHLAB_CHIQARISH:
if "*" in self.ruxsat_etilgan:
raise ValueError(
"Ishlab chiqarishda '*' ruxsat etilmaydi"
)
if not self.api_kalit:
raise ValueError("Ishlab chiqarishda api_kalit majburiy")
Sozlama._NUSXALAR += 1
self._id = Sozlama._NUSXALAR
# ═══ FABRIKA METODLARI ═══
@classmethod
def ishlab_chiqish(cls, nom: str = "dev", **kw) -> "Sozlama":
return cls(nom=nom, muhit=Muhit.ISHLAB_CHIQISH,
manzil=Manzil("localhost", 8000), **kw)
@classmethod
def sinov(cls, nom: str = "test", **kw) -> "Sozlama":
return cls(nom=nom, muhit=Muhit.SINOV,
manzil=Manzil("0.0.0.0", 8001),
ruxsat_etilgan=["localhost"], **kw)
@classmethod
def ishlab_chiqarish(cls, nom: str, api_kalit: str,
**kw) -> "Sozlama":
kw.setdefault("ruxsat_etilgan", ["wisar.uz", "api.wisar.uz"])
return cls(nom=nom, muhit=Muhit.ISHLAB_CHIQARISH,
manzil=Manzil("0.0.0.0", 443, ssl=True),
api_kalit=api_kalit, **kw)
@classmethod
def jsondan(cls, matn: str) -> "Sozlama":
m = json.loads(matn)
if "manzil" in m and isinstance(m["manzil"], str):
m["manzil"] = Manzil.parse(m["manzil"])
elif "manzil" in m and isinstance(m["manzil"], dict):
m["manzil"] = Manzil(**m["manzil"])
if "teglar" in m:
m["teglar"] = set(m["teglar"])
nomlar = {f.name for f in fields(cls) if f.init}
notogri = set(m) - nomlar
if notogri:
raise ValueError(f"Noma'lum maydonlar: {sorted(notogri)}")
return cls(**m)
@classmethod
def muhitdan(cls, muhit_ozg: dict[str, str],
prefiks: str = "APP_") -> "Sozlama":
m: dict[str, Any] = {}
for f in fields(cls):
if not f.init:
continue
kalit = f"{prefiks}{f.name.upper()}"
if kalit not in muhit_ozg:
continue
xom = muhit_ozg[kalit]
tur = f.type
if tur == "bool" or tur is bool:
m[f.name] = xom.lower() in ("1", "true", "ha")
elif tur == "int" or tur is int:
m[f.name] = int(xom)
elif "list" in str(tur):
m[f.name] = [q.strip() for q in xom.split(",")]
elif "set" in str(tur):
m[f.name] = {q.strip() for q in xom.split(",")}
else:
m[f.name] = xom
return cls(**m)
# ═══ AMALLAR ═══
def bilan(self, **ozgarishlar) -> "Sozlama":
"""⭐ replace() ning qulay o'ramchisi."""
return replace(self, **ozgarishlar)
def lugat(self, sirlar_bilan: bool = False) -> dict[str, Any]:
d = asdict(self)
d["muhit"] = str(self.muhit)
d["teglar"] = sorted(self.teglar)
d.pop("_id", None)
d.pop("yaratilgan", None)
if not sirlar_bilan:
d["api_kalit"] = "***" if self.api_kalit else ""
d["baza"].pop("_ulanish_url", None)
return d
def json(self, **kw) -> str:
return json.dumps(self.lugat(), ensure_ascii=False,
default=str, **kw)
@property
def url(self) -> str:
return self.manzil.url
print("1. Fabrika metodlari:\n")
s_dev = Sozlama.ishlab_chiqish()
s_test = Sozlama.sinov(teglar={"ci", "avtomatik"})
s_prod = Sozlama.ishlab_chiqarish("wisar-prod", api_kalit="sk-abc123")
for s in (s_dev, s_test, s_prod):
print(f" {str(s.muhit):<18} {s.url:<28} debug={s.debug}")
print(f" {'':<18} ruxsat: {s.ruxsat_etilgan}")
print(f"\n Ishlab chiqarish tekshiruvi:")
for tavsif, kw in [
("api_kalit yo'q", dict(nom="p", muhit=Muhit.ISHLAB_CHIQARISH,
ruxsat_etilgan=["wisar.uz"])),
("'*' ruxsat", dict(nom="p", muhit=Muhit.ISHLAB_CHIQARISH,
api_kalit="k", ruxsat_etilgan=["*"])),
("nom bo'sh", dict(nom=" ")),
]:
try:
Sozlama(**kw)
n = "⚠️ o'tdi"
except ValueError as e:
n = f"✅ ValueError: {e}"
print(f" {tavsif:<18} {n}")
print("\n\n2. ⭐ InitVar — parol saqlanmaydi:\n")
b = BazaSozlama(baza="wisar_prod", foydalanuvchi="app",
parol="juda-maxfiy-parol", hovuz_hajmi=20)
print(f" {b!r}\n")
print(f" parol nusxada: {'parol' in vars(b)} ⭐ saqlanmadi")
print(f" hasattr(b, 'parol'): {hasattr(b, 'parol')} ⚠️ chalg'ituvchi!")
print(f" Sabab: InitVar standart qiymati (= \"\") SINF atributi bo'lib")
print(f" qoladi: BazaSozlama.parol = {BazaSozlama.parol!r}. Nusxada esa yo'q.")
print(f" _parol_bor: {b._parol_bor}")
print(f" ulanish_url: {b.ulanish_url}")
print(f" ⭐ Parol XESHLANMAGAN ham, SAQLANMAGAN ham")
print("\n\n3. O'zgaruvchan sukutlar ajralgan:\n")
a1, a2 = Sozlama(nom="a"), Sozlama(nom="b")
a1.ruxsat_etilgan.append("qo'shildi")
a1.xususiyatlar["yangi"] = True
a1.teglar.add("teg")
print(f" a1.ruxsat_etilgan = {a1.ruxsat_etilgan}")
print(f" a2.ruxsat_etilgan = {a2.ruxsat_etilgan} ✅ ajralgan")
print(f" a1.xususiyatlar = {a1.xususiyatlar}")
print(f" a2.xususiyatlar = {a2.xususiyatlar} ✅")
print(f"\n a1.baza is a2.baza = {a1.baza is a2.baza} ✅ ajralgan")
print("\n\n4. replace / bilan:\n")
asl = Sozlama.ishlab_chiqish("asl")
yangi = asl.bilan(nom="yangi", manzil=Manzil("api.wisar.uz", 443,
ssl=True))
print(f" asl: nom={asl.nom!r}, url={asl.url}")
print(f" yangi: nom={yangi.nom!r}, url={yangi.url}")
print(f" asl o'zgarmadi: {asl.nom!r} ✅")
print(f"\n ⚠️ replace SATHIY nusxa:")
print(f" yangi.teglar is asl.teglar = {yangi.teglar is asl.teglar}")
print(f" ⭐ default_factory qayta ishlamaydi — mavjud qiymat ko'chadi")
print(f"\n init=False maydonlar:")
try:
replace(asl, debug=True)
except (ValueError, TypeError) as e:
print(f" replace(asl, debug=True) → ✅ {type(e).__name__}")
print("\n\n5. Serializatsiya:\n")
print(f" s_prod.lugat() (sirlarsiz):")
d = s_prod.lugat()
for k, v in list(d.items())[:8]:
print(f" {k:<18} {v!r}")
print(f"\n ⭐ api_kalit: {d['api_kalit']!r} (yashirilgan)")
print(f"\n JSON:")
for q in s_dev.json(indent=2).split("\n")[:12]:
print(f" {q}")
print(f"\n jsondan() bilan qayta yaratish:")
JSON = json.dumps({
"nom": "json-dan",
"muhit": "sinov",
"manzil": {"host": "api.local", "port": 9000},
"teglar": ["a", "b"],
})
s_json = Sozlama.jsondan(JSON)
print(f" {s_json.nom!r}, {s_json.url}, teglar={sorted(s_json.teglar)}")
try:
Sozlama.jsondan('{"nom": "x", "xato_maydon": 1}')
except ValueError as e:
print(f" Noma'lum maydon → ✅ ValueError: {e}")
print("\n\n6. Muhit o'zgaruvchilaridan:\n")
MUHIT_OZG = {
"APP_NOM": "muhitdan",
"APP_MUHIT": "sinov",
"APP_RUXSAT_ETILGAN": "localhost, 127.0.0.1, api.local",
"APP_TEGLAR": "ci,test",
"APP_API_KALIT": "sk-muhit",
}
s_env = Sozlama.muhitdan(MUHIT_OZG)
print(f" {s_env.nom!r}, muhit={s_env.muhit}")
print(f" ruxsat_etilgan = {s_env.ruxsat_etilgan}")
print(f" teglar = {sorted(s_env.teglar)}")
print("\n\n7. Versiya (frozen + order + slots):\n")
VERSIYALAR = [Versiya.parse(s) for s in
["2.1.0", "1.0", "2.0.5", "v3", "2.1.1"]]
print(f" Saralangan: {[str(v) for v in sorted(VERSIYALAR)]}")
print(f" Eng yangi: {max(VERSIYALAR)}")
print(f" Joriy: {Sozlama.VERSIYA}")
print(f"\n Hashable: {{v1, v1, v2}} → "
f"{len({Versiya(1), Versiya(1), Versiya(2)})} element")
v = Versiya(2, 1, 0)
try:
v.katta = 3
except Exception as e:
print(f" v.katta = 3 → ✅ {type(e).__name__}")
import sys
print(f"\n Xotira (slots=True): {sys.getsizeof(v)} bayt")
print(f" __dict__ bormi: {hasattr(v, '__dict__')}")
print("\n\n8. Maydonlar tahlili:\n")
print(f" {'Maydon':<18} {'init':<6} {'repr':<6} {'compare':<9} "
f"{'factory'}")
print(" " + "─" * 56)
for f in fields(Sozlama):
fac = "✅" if f.default_factory is not MISSING else ""
print(f" {f.name:<18} {f.init!s:<6} {f.repr!s:<6} "
f"{f.compare!s:<9} {fac}")
print(f"\n ClassVar (maydon emas): VERSIYA, _NUSXALAR")
print(f" Yaratilgan nusxalar: {Sozlama._NUSXALAR}")
print(f"""
⭐ BU LOYIHADA ISHLATILGAN:
@dataclass(frozen=True, slots=True, order=True) Versiya
@dataclass(kw_only=True) Sozlama, BazaSozlama
field(default_factory=...) o'zgaruvchan sukutlar
field(repr=False) sirlar (api_kalit)
field(compare=False) vaqt tamg'asi, _id
field(init=False) hisoblanadigan (debug, _id)
InitVar[str] parol — saqlanmaydi
ClassVar[...] VERSIYA, _NUSXALAR
__post_init__ tekshiruv, normallashtirish,
bog'liq qiymatlar
object.__setattr__ frozen ichida yozish
@classmethod fabrikalar ishlab_chiqish, sinov,
ishlab_chiqarish, jsondan, muhitdan
@property url, ulanish_url
replace() bilan() orqali
⭐ NATIJA: ~200 qator kod bilan to'liq konfiguratsiya
tizimi — tekshiruv, serializatsiya, meros, o'zgarmaslik.
""")Natijaning muhim qismi:
1. Fabrika metodlari:
ishlab_chiqish http://localhost:8000 debug=True
ruxsat: ['*']
ishlab_chiqarish https://0.0.0.0 debug=False
ruxsat: ['wisar.uz', 'api.wisar.uz']
Ishlab chiqarish tekshiruvi:
api_kalit yo'q ✅ ValueError: Ishlab chiqarishda api_kalit majburiy
'*' ruxsat ✅ ValueError: Ishlab chiqarishda '*' ruxsat etilmaydi
2. ⭐ InitVar — parol saqlanmaydi:
parol nusxada: False ⭐ saqlanmadi
hasattr(b, 'parol'): True ⚠️ chalg'ituvchi!
ulanish_url: postgresql://app:***@localhost:5432/wisar_prod
4. replace / bilan:
⚠️ replace SATHIY nusxa:
yangi.teglar is asl.teglar = True
7. Versiya (frozen + order + slots):
Saralangan: ['1.0.0', '2.0.5', '2.1.0', '2.1.1', '3.0.0']
Xotira (slots=True): 56 baytNima ko'rsatdi: 2.2, 2.3, 2.5, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"x = 5 ham maydon" |
Tur ko'rsatkichi kerak: x: int = 5 |
"dataclass turni tekshiradi" |
Faqat hujjat; pydantic tekshiradi |
"@dataclass __hash__ beradi" |
frozen=True kerak |
"asdict sathiy nusxa" |
Chuqur rekursiv nusxa |
"replace chuqur nusxa qiladi" |
Sathiy — konteynerlar bir obyekt |
"frozen to'liq o'zgarmas" |
Ichki list o'zgaradi |
| "Meros bilan tartib erkin" | Sukutsiz maydon sukutlidan keyin bo'lmaydi |
"ClassVar maydon" |
Ataylab maydon emas |
6. Keng tarqalgan xatolar va yechimlari
1. Tur ko'rsatkichi yo'q
@dataclass
class A:
x = 5 # ⚠️ maydon emas
x: int = 5 # ✅2. O'zgaruvchan sukut
teglar: list = [] # ❌ ValueError
teglar: list = field(default_factory=list) # ✅3. frozen da __post_init__
def __post_init__(self):
self.y = self.x * 2 # ❌ FrozenInstanceError
object.__setattr__(self, "y", self.x*2) # ✅4. Merosda sukutsiz maydon
@dataclass
class B(A):
c: int # ❌ TypeError
c: int = 0 # ✅
# yoki @dataclass(kw_only=True)5. property nomi maydon bilan bir xil
@dataclass
class A:
x: int = 0
@property
def x(self): ... # ⚠️ to'qnashuv
# ✅ _x: int = 0 + property x6. frozen ichida list
@dataclass(frozen=True)
class A:
lst: list = field(default_factory=list)
a.lst.append(1) # ⚠️ o'tadi!
lst: tuple = () # ✅7. Hisoblangan maydonni saqlash
yuza: float = field(init=False) # ⚠️ eskiradi
@property
def yuza(self): ... # ✅8. eq=True + hashable kerak
@dataclass
class A:
x: int
{A(1)} # ❌ unhashable
@dataclass(frozen=True) # ✅7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8.3-dars (o'tilgan):
__init__va sukut tuzoqlari - 8.11, 8.12-darslar:
__repr__,__eq__,__hash__ - 8.15-dars:
propertyva deskriptorlar - 8.19-dars:
__slots__ - 7.14-dars: tur ko'rsatkichlari
attrs,pydantic,msgspec— muqobillar- PEP 557: Data Classes
8. Eng yaxshi amaliyotlar
O'zgaruvchan sukut —
field(default_factory=...). Har doim.Ma'lumot obyekti bo'lsa
frozen=True. Hashable va xavfsiz.Ko'p maydon bo'lsa
kw_only=True. O'qiladigan va kengaytiriladigan.Sirlar —
field(repr=False). Jurnalga tushmasin.Hisoblangan qiymat —
@property.field(init=False)eskiradi.Tekshiruv —
__post_init__da. Yokipydantic.InitVar— saqlanmasligi kerak bo'lgan argument uchun.Ko'p nusxa bo'lsa
slots=True. 3× kam xotira.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
1. @dataclass
class A: x: int = 1
print(A() == A(), A.__hash__)
2. @dataclass(frozen=True)
class A: x: int = 1
print(A.__hash__ is not None)
3. @dataclass
class A:
x = 5
y: int = 10
print([f.name for f in fields(A)])
4. @dataclass
class A: x: int = 0
try:
@dataclass
class B(A): y: int
except TypeError: print("xato")
5. @dataclass
class A: lst: list = field(default_factory=list)
a, b = A(), A()
a.lst.append(1)
print(b.lst)
6. @dataclass
class A: x: int
print(asdict(A(1)))
7. @dataclass
class A: x: list
a = A([1])
print(asdict(a)["x"] is a.x)
8. @dataclass(order=True)
class A: x: int; y: int
print(A(1, 2) < A(1, 3), A(2, 0) < A(1, 9))
9. @dataclass
class A:
x: int
JAMI: ClassVar[int] = 0
print(len(fields(A)))
10. @dataclass
class A: x: int = 0
print(replace(A(1), x=2))
11. @dataclass(frozen=True)
class A: lst: tuple = ()
a = A((1, 2))
print(hash(a) is not None)
12. @dataclass
class A:
x: int
y: int = field(init=False, default=0)
def __post_init__(self): self.y = self.x * 2
print(A(5))Javoblar
True NoneTrue['y']—xtur ko'rsatkichisizxato—A.xsukutli,B.ysukutsiz →__init__(self, x=0, y)yaroqsiz[]{'x': 1}False— chuqur nusxaTrue False1—ClassVarmaydon emasA(x=2)TrueA(x=5, y=10)
Vazifa 2: Xatolarni tuzating
1. @dataclass
class A: teglar: list = []
2. @dataclass
class A:
x = 5
3. @dataclass(frozen=True)
class A:
x: int
y: int = field(init=False, default=0)
def __post_init__(self): self.y = self.x * 2
4. @dataclass
class B(A): c: int # A da sukutli maydon bor
5. @dataclass
class A:
x: int
yuza: float = field(init=False, default=0)
6. @dataclass
class A: parol: str
7. @dataclass
class A: x: int
s = {A(1)}
8. @dataclass(frozen=True)
class A: lst: list = field(default_factory=list)Javoblar
1. teglar: list = field(default_factory=list)
2. x: int = 5
3. object.__setattr__(self, "y", self.x * 2)
4. c: int = 0 yoki @dataclass(kw_only=True)
5. @property def yuza(self): ...
6. parol: str = field(repr=False) (yoki InitVar)
7. @dataclass(frozen=True)
8. lst: tuple = () (frozen bilan o'zgarmas tur)Vazifa 3: Buyurtma modeli
Yozing:
Mahsulot—frozen,slots,orderElement— mahsulot + soni,@property jamiBuyurtma—kw_only, elementlar ro'yxati__post_init__da tekshiruvInitVarbilan chegirma kodi (saqlanmasin)asdict,replace, fabrika metodlari- Sirlar
reprda yo'q
Vazifa 4: dataclass tekshiruvchisi
Vosita yozing:
- O'zgaruvchan sukutlarni topsin (
fieldsiz) - Tur ko'rsatkichisiz "maydonlar"ni
frozenbo'lmagan, lekin__hash__kerak sinflarnifield(init=False)bilan hisoblangan (eskirishi mumkin)- Sirlar
repr=Falsesiz ekanini - Merosdagi tartib muammolarini
Vazifa 5: NamedTuple bilan solishtirish
Bir modelni to'rt usulda yozing:
- Oddiy sinf
NamedTupledataclassdataclass(frozen=True, slots=True)
Solishtiring: kod hajmi, xotira, tezlik, imkoniyatlar.
Vazifa 6: JSON serializator
- Har
dataclassni JSON ga o'girsin - Ichma-ich
dataclasslarni ham datetime,Decimal,Enum,setni qo'llab-quvvatlasinfield(metadata={"json": "boshqa_nom"})— nom o'zgartirishrepr=Falsemaydonlarni chiqarmasin- Teskari: JSON dan
dataclassyaratish
Vazifa 7: O'ylash
Nega dataclass tur tekshiruvini qilmaydi — tur ko'rsatkichlari majburiy bo'lsa ham?
Javob
Chunki tur ko'rsatkichlari Pythonda hech qachon ish vaqtida tekshirilmaydi (7.14-dars), va dataclass bu qoidani buzmasligi kerak.
1. Tur ko'rsatkichi — hujjat
@dataclass
class Nuqta:
x: int
y: int
n = Nuqta("emas", [1, 2]) # ✅ ishlaydi!
n.x # 'emas' dataclass x: int ni faqat maydon e'loni sifatida ishlatadi — turning o'zi e'tiborga olinmaydi (deyarli).
2. Nega tekshirmaydi
a) Falsafaga zid
Python tur ko'rsatkichlarini hech qayerda ish vaqtida tekshirmaydi:
def f(x: int) -> str:
return x * 2
f("ab") # ✅ 'abab'Agar dataclass tekshirsa, bu istisno bo'lardi va chalkashlik tug'dirardi:
"Nega
dataclasstekshiradi, oddiy funksiya yo'q?"
b) Narxi katta
@dataclass
class A:
m: dict[str, list[tuple[int, str]]]Bu turni to'liq tekshirish uchun butun tuzilmani aylanib chiqish kerak:
isinstance(m, dict)
all(isinstance(k, str) for k in m)
all(isinstance(v, list) for v in m.values())
all(isinstance(t, tuple) and len(t) == 2 and
isinstance(t[0], int) and isinstance(t[1], str)
for v in m.values() for t in v)Har obyekt yaratishda O(n) yoki yomonroq.
c) Ba'zi turlarni tekshirib bo'lmaydi
from typing import Callable, TypeVar, Protocol, Any
@dataclass
class A:
f: Callable[[int], str] # ⚠️ imzoni tekshirib bo'lmaydi
x: Any # ⚠️ nima tekshirish kerak?
y: "KelajakdaAniqlanadi" # ⚠️ satr — hali mavjud emas
z: TypeVar("T") # ⚠️d) Duck typing buzilardi
@dataclass
class A:
lst: list[int]
A((1, 2, 3)) # tuple — ⚠️ tekshiruv rad etardi
A(range(3)) # range — ⚠️ ham Pythonda list[int] odatda "iteratsiya qilinadigan sonlar" degani, qat'iy list emas.
3. Nima uchun tur ko'rsatkichi MAJBURIY
Agar tekshirilmasa, nega kerak?
Uch sabab:
a) Maydonni ajratish
@dataclass
class A:
x: int = 5 # ⭐ MAYDON
y = 10 # ⭐ oddiy sinf atributiTur ko'rsatkichi — sintaktik signal: "bu maydon". Boshqa yo'l yo'q edi.
b) __annotations__ dan o'qish
@dataclass
class A:
x: int
y: str = "a"
A.__annotations__ # {'x': int, 'y': str} dataclass aynan shu lug'atni o'qiydi:
# dataclasses.py dan (soddalashtirilgan):
for nom, tur in cls.__dict__.get('__annotations__', {}).items():
maydonlar.append(_get_field(cls, nom, tur))c) mypy uchun
@dataclass
class Nuqta:
x: int
y: int
Nuqta("a", "b")
# mypy: Argument 1 to "Nuqta" has incompatible type "str"; expected "int" Statik tekshiruv ishlaydi — dataclass mypy uchun __init__ imzosini beradi.
4. ClassVar va InitVar — istisnolar
Ikki holatda dataclass turni haqiqatan tekshiradi:
from typing import ClassVar
from dataclasses import InitVar
@dataclass
class A:
x: ClassVar[int] = 0 # ⭐ maydon EMAS
y: InitVar[str] = "" # ⭐ __post_init__ ga
z: int = 0 # oddiy maydonLekin bu ham matn darajasida:
# dataclasses.py:
def _is_classvar(a_type, typing):
return (a_type is typing.ClassVar
or (type(a_type) is typing._GenericAlias
and a_type.__origin__ is typing.ClassVar))
def _is_type(annotation, cls, a_module, a_type, is_type_predicate):
# ⚠️ Satr annotatsiyalar uchun REGEX bilan tekshiriladi!
match = _MODULE_IDENTIFIER_RE.match(annotation)
... from __future__ import annotations bilan barcha annotatsiyalar satr bo'ladi, va dataclass "ClassVar[int]" satrini regex bilan tekshiradi. Bu — mo'rt, lekin ishlaydi.
5. O'zgaruvchan sukut — yagona haqiqiy tekshiruv
@dataclass
class A:
x: list = [] # ❌ ValueErrorBu qiymat tekshiruvi, tur emas:
# dataclasses.py:
if f.default.__class__.__hash__ is None:
raise ValueError(f'mutable default {type(f.default)} for field '
f'{f.name} is not allowed: use default_factory') Mezon — __hash__ bor-yo'qligi. list, dict, set da __hash__ = None.
Bu to'liq emas:
@dataclass
class A:
x: object = SomeObject() # ⚠️ hashable, lekin o'zgaruvchan bo'lishi mumkin6. Muqobillar — tekshiradiganlar
| Kutubxona | Tekshiruv | Tezlik | Bog'liqlik |
|---|---|---|---|
dataclasses |
Tez | Yo'q | |
attrs |
Ixtiyoriy (validator) |
Tez | Kichik |
pydantic |
To'liq + o'girish | Sekinroq (v2 da Rust) | |
msgspec |
To'liq | Eng tez | |
beartype |
Dekorator | Tez |
pydantic misoli:
from pydantic import BaseModel, Field, field_validator
class Nuqta(BaseModel):
x: int
y: int = Field(ge=0, le=100)
@field_validator("x")
@classmethod
def x_musbat(cls, v):
if v < 0: raise ValueError("musbat bo'lsin")
return v
Nuqta(x="5", y=10) # ✅ "5" → 5 O'GIRILADI
Nuqta(x="abc", y=10) # ❌ ValidationError
Nuqta(x=1, y=200) # ❌ ValidationError pydantic o'giradi ham — bu tashqi ma'lumot (JSON, form) uchun juda foydali.
attrs misoli:
import attrs
@attrs.define
class Nuqta:
x: int = attrs.field(validator=attrs.validators.instance_of(int))
y: int = attrs.field(validator=[
attrs.validators.instance_of(int),
attrs.validators.ge(0),
])7. Qachon qaysi
# ⭐ 1. Ichki ma'lumot, tur allaqachon to'g'ri
@dataclass
class Nuqta:
x: float
y: float
# ⭐ 2. Tashqi ma'lumot (API, JSON, form)
class NuqtaSorov(BaseModel): # pydantic
x: float
y: float
# ⭐ 3. Qo'lda tekshiruv yetsa
@dataclass
class Nuqta:
x: float
y: float
def __post_init__(self):
if not isinstance(self.x, (int, float)):
raise TypeError(...)
# ⭐ 4. Juda ko'p obyekt, tezlik muhim
@dataclass(frozen=True, slots=True)
class Nuqta:
x: float
y: float8. Tezlik farqi
import timeit
# dataclass
timeit.timeit(lambda: Nuqta(1.0, 2.0), number=1_000_000)
# ~0.35s
# pydantic v2
timeit.timeit(lambda: NuqtaModel(x=1.0, y=2.0), number=1_000_000)
# ~1.2s (v1 da ~4s edi)
# oddiy tuple
timeit.timeit(lambda: (1.0, 2.0), number=1_000_000)
# ~0.05s dataclass — tekshiruvsiz, shuning uchun tez. pydantic v2 Rust da yozilgan va ancha tezlashdi, lekin hali ham 3× sekinroq.
9. Kelajak
PEP 681 3.11-bob — @dataclass_transform:
from typing import dataclass_transform
@dataclass_transform()
def mening_modelim(cls): ... Bu mypy ga "bu dekorator dataclass kabi ishlaydi" deb aytadi. pydantic, attrs, SQLAlchemy shuni ishlatadi.
PEP 649 3.14-bob — kechiktirilgan annotatsiya hisoblash. Bu dataclass uchun ClassVar aniqlashni soddalashtiradi (regex o'rniga haqiqiy obyekt).
10. Xulosa
dataclass tur tekshirmaydi, chunki:
- Python falsafasi — tur ko'rsatkichlari ish vaqtida tekshirilmaydi
- Narxi — chuqur tekshiruv O(n) yoki yomonroq
- Mumkin emas —
Callable,Any,TypeVar, oldinga havolalar - Duck typing —
tuplelist[int]o'rniga o'tishi mumkin - Standart kutubxona — bog'liqliksiz va tez bo'lishi kerak
Va tur ko'rsatkichi majburiy, chunki u:
- Maydonni oddiy atributdan ajratadi
__annotations__orqalidataclassga ma'lumot beradimypyuchun__init__imzosini yaratadi
Umumiy naqsh: Python qatlamlarni ajratadi — dataclass kod generatsiyasi, mypy statik tekshiruv, pydantic ish vaqtidagi validatsiya. Har biri o'z ishini qiladi va siz kerakli qatlamni tanlaysiz.
Nimani mustahkamlaydi: 2.1, 2.8-bo'limlar.
Xulosa
Bu darsda dataclass ni to'liq o'rgandik.
Eng muhim uch fikr:
dataclass— kod generatori, tur tekshiruvchisi emas. U__annotations__dagi maydonlarni o'qib__init__,__repr__,__eq__(va sozlamalarga qarab boshqalarni) yozadi. Tur ko'rsatkichi majburiy, lekin faqat maydonni ajratish uchun — ish vaqtida tekshirilmaydi. Tekshiruv kerak bo'lsa —__post_init__yokipydantic.O'zgaruvchan sukut tuzog'i taqiqlangan.
teglar: list = []—ValueErrorsinf yaratish paytida.field(default_factory=list)ishlating. Bu —dataclassning oddiy sinfga nisbatan eng katta amaliy afzalligi: 8.3-darsda ko'rgan jimgina tuzoq mumkin emas bo'lib qoladi.__hash__faqatfrozen=Truebilan keladi. Sukut bo'yicha (eq=True, frozen=False)__hash__Nonebo'ladi — obyekt to'plamga solinmaydi. Bu ataylab: o'zgaruvchan hashable obyekt to'plamda topilmay qoladi (8.12-dars). Ma'lumot obyektlari uchunfrozen=True, slots=True— sukut tanlov bo'lsin.
Keyingi darsda abstrakt asos sinflarni (ABC) ko'ramiz: @abstractmethod, collections.abc, register() va interfeys loyihalash.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!