Ачааллж байна...
Course 2-т та @dataclass-ийг хэрэглэж, __init__, __repr__, __eq__ гэх мэт method-уудыг гараар бичихгүйгээр өгөгдлийн class бүтээсэн. Хичээл 5.4-т бид түүнийг дотроос нь харсан: dataclass бол class decorator бөгөөд шинэ боодол буцаадаггүй, ижил class-ийг type hint-үүдээр нь уншаад, тохирох method-уудыг үүсгэж нэмдэг. Тэр хичээлд бид @dataclass(frozen=True) хаалттай хэлбэрийг argument-тай decorator гэж таниад, гүн боломжуудыг энэ хичээл хүртэл хойш тавьсан.
Энэ хичээлд dataclass-ийн гурван гүн боломжийг судална, тус бүр бодит асуудлыг шийддэг. Эхнийх нь field(default_factory=...). Өмнөх хичээлийн өөрчлөгдөж болох анхдагч утгын урхийг dataclass хэрхэн илрүүлж, зөв шийддэгийг харна. Хоёр дахь нь frozen=True: объектыг үүссэний дараа өөрчлөгдөхгүй болгодог. Энэ нь мөнгөн дүн, координат, огноо зэрэг "утга" шинжтэй өгөгдөлд хамгийн тохиромжтой бөгөөд Хичээл 3.3-ын lru_cache-ийн “unhashable” алдааг шийддэг. Гурав дахь нь __post_init__: dataclass-ийн үүсгэсэн __init__-ийн дараа ажилладаг method бөгөөд шалгалт, хэвийн болгох, тооцоолсон талбар нэмэхэд хэрэглэгддэг.
Хичээл бүрийн нэгэн адил бид эдгээрийн ард юу болдгийг харна. dataclass кодыг харагдахгүйгээр үүсгэдэг тул түүний __init__ ойролцоогоор ямар харагддагийг бичиж, объект үүсэх үед алхам бүрт юу болдгийг trace хийнэ. Энэ бүлгийн өмнөх гурван хичээлийн мэдлэг, classmethod, method-ын төрлүүд, class attribute-ын урхи бүгд энд нэгдэнэ.
Барааны агуулахын бүртгэлийн хуудсыг төсөөлөөд үзээрэй. Агуулахын эрхлэгч шинэ барааны маягт бэлдэх ажилтай. Тэр маягтын загварыг нэг удаа зохиодог: ямар талбарууд байх вэ, аль нь заавал бөглөх, аль нь анхдагч утгатай. Дараа нь шинэ бараа ирэх бүрт тэр загвараар шинэ маягт хэвлэж, бөглөнө. dataclass бол тэр загвар зохиогч: та талбаруудыг жагсааж өгнө, тэр маягт хэвлэх машиныг, __init__-ийг, бүтээж өгнө.
Одоо гурван нарийн асуудал. Нэгдүгээрт, маягт бүрт "хавсралт" гэсэн хоосон дугтуй байх ёстой. Хэрэв эрхлэгч ганц дугтуй бэлдээд маягт бүрт түүнийг хавчуулбал бүх бараа нэг дугтуйг хуваалцаж, нэг барааны баримт бусдынхтай холилдоно. Зөв арга нь маягт хэвлэх бүрт шинэ дугтуй гаргах: дугтуйн үйлдвэр. Энэ бол default_factory.
Хоёрдугаарт, зарим маягт, жишээлбэл төлбөрийн баримт, бөглөгдсөний дараа хэзээ ч засагдах ёсгүй. Ийм маягтыг лацдана. Засвар хэрэгтэй бол хуучныг нь үлдээж, шинэ маягт бөглөнө. Энэ бол frozen.
Гуравдугаарт, маягт бөглөгдсөний дараа ахлах ажилтан түүнийг шалгаж, тамга дарна: тоо зөв үү, огноо утга учиртай юу, нэмэлт тооцоолол хэрэгтэй юу. Энэ бол __post_init__.
Өмнөх хичээлүүдийн Student-ийг dataclass болгоё:
python
from dataclasses import dataclass
import inspect
@dataclass
class Student:
name: str
score: int
group: str = "тодорхойгүй"
s = Student("Бат", 95)
print(s)
print(s == Student("Бат", 95))
print(inspect.signature(Student))Student(name='Бат', score=95, group='тодорхойгүй')
True
(name: str, score: int, group: str = 'тодорхойгүй') -> NoneГурван талбар, гурван type hint, нэг анхдагч утга. dataclass эдгээрийг уншаад __init__-ийг үүсгэсэн: inspect.signature түүний гарын үсгийг харуулж байна, Хичээл 5.2-ын хэрэгсэл. Мөн __repr__ уншигдахуйц хэвлэлт өгсөн, __eq__ хоёр объектыг талбаруудаар нь харьцуулсан. Үүсгэсэн __init__ ойролцоогоор ийм харагдана:
python
def __init__(self, name: str, score: int, group: str = "тодорхойгүй"):
self.name = name
self.score = score
self.group = groupЭнэ бол Course 2-т бидний гараар бичдэг байсан яг тэр код. dataclass зүгээр л уйтгартай давталтыг бидний өмнөөс бичдэг. Талбарууд class-ийн биед бичигдсэн ч тэдгээр нь Хичээл 7.3-ын class attribute биш: dataclass тэдгээрийг "маягтын талбарууд" гэж уншиж, __init__ дотор self дээр оноох код үүсгэдэг. Тэгэхээр объект бүр өөрийн name, score, group-тэй, тус бүрийн __dict__-д. Харин анхдагч утга "тодорхойгүй" нь class-ийн бие дотор байгаа тул нэг удаа үүсдэг. String өөрчлөгддөггүй тул энэ аюулгүй. Өөрчлөгддөг утгын хувьд асуудал гарна.
Жишээ 1: default_factory — анхдагч утгын урхийг зөв шийдэх
Өмнөх хичээлийн шошгоны жагсаалтыг dataclass-д нэмэх гэж оролдъё:
python
from dataclasses import dataclass
@dataclass
class Student:
name: str
tags: list = []Traceback (most recent call last):
...
ValueError: mutable default <class 'list'> for field tags is not allowed: use default_factoryАнхаар: энэ алдаа объект үүсгэх үед биш, class тодорхойлогдох үед, Хичээл 5.1-ийн "тодорхойлох цагт" гарсан. Мессежийг уншъя: “tags талбарт <class ‘list’> төрлийн өөрчлөгдөж болох анхдагч утга зөвшөөрөгдөхгүй: default_factory хэрэглэ”. dataclass өмнөх хичээлийн урхийг таниад, урхинд унахаас өмнө биднийг зогсоосон. Мөн шийдлийг ч мессеждээ хэлж байна. Энэ бол Хичээл 6.4-т бидний сан дээр хэрэгжүүлсэн "тохиргооны цагт алдааг эрт илрүүлэх" зарчмын стандарт сан дахь жишээ.
Зөв хувилбар:
python
from dataclasses import dataclass, field
@dataclass
class Student:
name: str
tags: list = field(default_factory=list)
bat = Student("Бат")
saraa = Student("Сараа")
bat.tags.append("тэтгэлэгтэй")
print(bat)
print(saraa)
print(bat.tags is saraa.tags)Student(name='Бат', tags=['тэтгэлэгтэй'])
Student(name='Сараа', tags=[])
Falsefield(default_factory=list) нь dataclass-д хэлж байна: "энэ талбарын анхдагч утгыг нэг удаа биш, объект үүсэх бүрт list()-ийг дуудаж үүсгэ". list-ийг хаалтгүйгээр өгсөнийг анзаараарай. Хичээл 3.1-ээс хойшхи "функцийг утга мэт дамжуулах" санаа: dataclass-д list функцийг өгсөн, үр дүнг нь биш. Үүсгэсэн __init__ ойролцоогоор:
python
def __init__(self, name, tags=<factory>):
self.name = name
self.tags = list() if tags is <factory> else tags<factory> нь dataclass-ийн дотоод тусгай тэмдэглэгээ: "энэ argument өгөгдөөгүй". Тэр тохиолдолд list() шинээр дуудагдана. Энэ бол өмнөх хичээлийн None загвартай яг ижил санаа, гэхдээ гараар бичих шаардлагагүй. Trace хийвэл: Student("Бат") үүсэхэд list() дуудагдаж, шинэ хоосон list Батын __dict__-д бичигдэнэ. Student("Сараа") үүсэхэд list() дахин дуудагдаж, өөр шинэ list. Сүүлийн мөрийн False хоёр list өөр объект гэдгийг баталж байна.
default_factory-д ямар ч argument-гүй дуудагдах зүйл өгч болно: dict, set, эсвэл lambda. Жишээлбэл шинэ сурагч бүр "шинэ" гэсэн шошготой эхлэх бол field(default_factory=lambda: ["шинэ"]). Lambda объект үүсэх бүрт дуудагдаж, шинэ list буцаана.
Жишээ 2: frozen — өөрчлөгдөхгүй утга
Одоо мөнгөн дүнг төлөөлдөг class бүтээе. Мөнгөн дүн бол "утга": 5000 төгрөг бол 5000 төгрөг, түүнийг "өөрчлөх" нь утгагүй. Харин шинэ дүн гаргах нь утгатай. Ийм өгөгдөлд frozen тохиромжтой:
python
from dataclasses import dataclass
@dataclass(frozen=True)
class Money:
amount: int
currency: str = "MNT"
price = Money(12500)
print(price)
price.amount = 1Money(amount=12500, currency='MNT')
Traceback (most recent call last):
...
dataclasses.FrozenInstanceError: cannot assign to field 'amount'@dataclass(frozen=True) нь Хичээл 5.3-ын argument-тай decorator хэлбэр. frozen=True нь dataclass-д объект үүсч дууссаны дараа талбарт оноохыг хориглох код нэмэхийг хэлж байна. Мессеж: “amount талбарт оноох боломжгүй”. FrozenInstanceError бол dataclasses модулийн тусгай алдаа, "хөлдөөсөн объектын алдаа". Зүйрлэлийн лацдасан маягт.
Тэгвэл үнийг өөрчлөх шаардлага гарвал? Хуучныг өөрчлөхгүй, шинийг үүсгэнэ. dataclasses модуль үүнд зориулсан replace() функцтэй:
python
from dataclasses import replace
discounted = replace(price, amount=11000)
print(price)
print(discounted)Money(amount=12500, currency='MNT')
Money(amount=11000, currency='MNT')replace нэг талбарыг өөрчилсөн шинэ объект буцаасан, анхных хэвээр. Энэ хэв маяг яагаад хэрэгтэй вэ? Өөрчлөгдөхгүй объектыг програмын хэдэн ч газар хуваалцахад аюулгүй. Хичээл 7.3-ын урхи, нэг объектын өөрчлөлт бусдад чимээгүй нөлөөлөх, энд огт гарахгүй, учир нь хэн ч өөрчилж чадахгүй. Мөн Бүлэг 13-т threading-тэй ажиллахад өөрчлөгдөхгүй өгөгдөл хамгийн найдвартай.
frozen-ийн хоёр дахь, магадгүй илүү чухал үр дүн: объект hash хийгдэх боломжтой болно. Хичээл 3.3-ын lru_cache-ийг санаарай: тэр list argument-ыг “unhashable type” гэж татгалзсан. Dict-ийн түлхүүр, set-ийн элемент, кэшийн argument бүгд hash хийгдэх боломжтой байх ёстой. frozen-гүй dataclass-ийг set-д хийж үзье:
python
@dataclass
class MutableMoney:
amount: int
currency: str = "MNT"
prices = {MutableMoney(5000), MutableMoney(5000)}Traceback (most recent call last):
...
TypeError: unhashable type: 'MutableMoney'frozen-гүй dataclass hash хийгдэхгүй. Шалтгаан нь логик: хэрэв объект set дотор байхад түүний amount өөрчлөгдвөл, set түүнийг буруу байрлалд хадгалсан болно. Тиймээс dataclass өөрчлөгдөж болох объектын hash-ийг санаатайгаар хаадаг. frozen хувилбартай:
python
from functools import lru_cache
prices = {Money(5000), Money(5000), Money(7000)}
print(prices)
@lru_cache(maxsize=None)
def with_vat(money):
return Money(round(money.amount * 1.1), money.currency)
print(with_vat(Money(5000)))
print(with_vat.cache_info()){Money(amount=5000, currency='MNT'), Money(amount=7000, currency='MNT')}
Money(amount=5500, currency='MNT')
CacheInfo(hits=0, misses=1, maxsize=None, currsize=1)Set хоёр ижил Money-г нэг гэж таньсан: __eq__ ба __hash__ хоёулаа талбаруудаар ажилладаг. lru_cache Money argument-ыг асуудалгүй хүлээн авсан. Хичээл 3.3-ын урхи шийдэгдсэн: кэшлэх функцэд нийлмэл өгөгдөл өгөх шаардлагатай бол түүнийг frozen dataclass болго.
Нэг шударга анхааруулга: frozen бол "гүехэн". Хэрэв frozen dataclass list талбартай бол та тэр талбарт шинэ list оноож чадахгүй ч, list-ийн дотрыг append-ээр өөрчилж чадна. Хичээл 4.2 ба 7.3-ын "өөрчлөх ба солих"-ын ялгаа энд дахин: frozen зөвхөн солихыг хориглодог. Мөн ийм объект hash хийгдэх үед доторх list hash хийгдэхгүй тул алдаа гарна. Жинхэнэ өөрчлөгдөхгүй объект хүсвэл frozen dataclass-ийн талбаруудыг ч өөрчлөгдөхгүй төрлүүд байлга: list-ийн оронд tuple.
Жишээ 3: __post_init__ — шалгалт ба тооцоолсон талбар
Хичээл 7.2-т Student-ийн __init__ оноо 0-100-ийн хооронд байгааг шалгадаг байсан. dataclass __init__-ийг бидний өмнөөс бичдэг бол шалгалтыг хаана хийх вэ? dataclass тусгай нэртэй method хайдаг: хэрэв class-д __post_init__ байвал үүсгэсэн __init__ өөрийн ажлыг дуусгасны дараа түүнийг дуудна.
python
from dataclasses import dataclass, field
@dataclass
class Student:
name: str
score: int
grade: str = field(init=False)
def __post_init__(self):
self.name = self.name.strip()
if not 0 <= self.score <= 100:
raise ValueError(f"Оноо 0-100 хооронд байх ёстой, {self.score} ирлээ")
self.grade = self._grade_for(self.score)
@staticmethod
def _grade_for(score):
if score >= 90:
return "A"
if score >= 75:
return "B"
if score >= 60:
return "C"
return "F"
print(Student(" Бат ", 95))
print(Student("Сараа", 72))
Student("Ану", 130)Student(name='Бат', score=95, grade='A')
Student(name='Сараа', score=72, grade='C')
Traceback (most recent call last):
...
ValueError: Оноо 0-100 хооронд байх ёстой, 130 ирлээ__post_init__ гурван ажил хийж байна: нэрийн хоёр талын зайг арилгах (хэвийн болгох), оноог шалгах, үнэлгээг тооцоолох. grade талбар field(init=False)-тэй: энэ нь dataclass-д "энэ талбарыг __init__-ийн argument болгох хэрэггүй" гэж хэлж байна. Хэрэглэгч үнэлгээг өгөхгүй, тэр онооноос тооцоологдоно. Гэвч grade нь repr-д харагдаж, __eq__-д оролцоно. _grade_for бол Хичээл 7.2-ын дүрмээр staticmethod: оноо авч үнэлгээ буцаадаг, self ч, cls ч хэрэггүй, гэхдээ Student-ийн өөрийн дүрэм. Нэрийн эхэн дэх доогуур зураас нь “class-ийн дотоод хэрэгсэл, гаднаас хэрэглэх зориулалтгүй” гэсэн Python-ий уламжлал.
Trace: Student(“ Бат “, 95) дуудагдахад:
Алхам 1 (үүсгэсэн __init__). self.name = “ Бат “, self.score = 95. grade init=False тул оноогдохгүй. Объектод: name = “ Бат “, score = 95.
Алхам 2 (__post_init__ дуудагдах). __init__ төгсгөлдөө self.__post_init__() дуудна.
Алхам 3 (хэвийн болгох). self.name = "Бат". Объектод: name = "Бат", score = 95.
Алхам 4 (шалгалт). 0 <= 95 <= 100 үнэн, алгасна.
Алхам 5 (тооцоолсон талбар). self._grade_for(95) нь “A” буцаана. Объектод: name = "Бат", score = 95, grade = “A”.
Ану-гийн тохиолдолд Алхам 4 ValueError шидэж, объект үүсэхгүй. Хичээл 7.1-ийн "бүх хаалга нэг коридороор" санаа энд ч хүчинтэй. Хэрэв энэ dataclass-д from_string classmethod нэмбэл, тэр cls(...)-ээр үүсгэсэн __init__-ийг дуудаж, тэр нь __post_init__-ийг дуудах тул шалгалт автоматаар хэрэглэгдэнэ.
frozen dataclass-д __post_init__ хэрэглэх нарийн зүйл бий: frozen объектод self.grade = ... гэж оноох нь FrozenInstanceError өгнө, __post_init__ дотор ч. Python-ий баримт бичиг энэ тохиолдолд object.__setattr__(self, "grade", ...) гэсэн тойрох замыг санал болгодог. Энэ нь frozen-ийн хамгаалалтыг зөвхөн объект бүтээгдэх явцад тойрдог. Энгийн тохиолдолд frozen dataclass-д тооцоолсон талбар нэмэхийн оронд Хичээл 5.4-ын property ашиглах нь илүү цэвэр.
Жишээ 4: бүгдийг нийлүүлбэл
Энэ бүлгийн дөрвөн хичээлийн мэдлэгийг нэг dataclass-д нэгтгэе: Хичээл 7.1-ийн LogRecord.
python
from dataclasses import dataclass, field
@dataclass(frozen=True)
class LogRecord:
VALID_LEVELS = ("INFO", "WARNING", "ERROR")
time: str
level: str
user: str
duration_ms: int
tags: tuple = field(default_factory=tuple)
def __post_init__(self):
if self.level not in self.VALID_LEVELS:
raise ValueError(f"Танигдаагүй түвшин: {self.level}")
@classmethod
def from_line(cls, line):
date, time, level, rest = line.split(" ", 3)
fields = dict(pair.split("=", 1) for pair in rest.split() if "=" in pair)
return cls(time, level, fields["user"], int(fields["duration_ms"]))
r = LogRecord.from_line("2026-10-09 08:15:40 ERROR user=saraa action=payment duration_ms=230")
print(r)
print(r in {r})LogRecord(time='08:15:40', level='ERROR', user='saraa', duration_ms=230, tags=())
Truefrozen: log бичлэг бол түүхэн баримт, өөрчлөгдөх ёсгүй, мөн set-д хийгдэх боломжтой. VALID_LEVELS бол type hint-гүй тул dataclass талбар биш, Хичээл 7.3-ын class attribute: бүх бичлэгт нэг, тогтмол, tuple тул өөрчлөгдөхгүй. dataclass зөвхөн type hint-тэй нэрсийг талбар гэж үздэг. tags-ийн default_factory=tuple нь өөрчлөгдөхгүй анхдагч утга өгнө, frozen-ийн гүехэн байдлын асуудлаас зайлсхийнэ. __post_init__ түвшинг шалгаж, тэр шалгалт self.VALID_LEVELS-ээр хандана, удамшсан class өөр жагсаалт тодорхойлж болно. from_line бол Хичээл 7.1-ийн туслах хаалга, cls(...)-ээр __init__ ба __post_init__-ийг дамжина. Арван гурван хичээлийн санаа нэг жижиг class-д.
Хүсвэл Жишээ 2-ын Money-д __post_init__ нэмж, сөрөг дүнг хориглож болно. frozen-тэй хамт оноолт хийхгүй, зөвхөн шалгалт хийх тул тойрох зам шаардлагагүй. Сонирхвол frozen dataclass-д list талбар нэмж, append хийгээд, дараа нь түүнийг set-д хийж үзээрэй: аль үйлдэл ажиллах, аль нь алдаа өгөх вэ? Мөн Жишээ 3-ын Student-ийн grade талбарыг field(init=False)-ийн оронд property болгож, хоёр хувилбарын repr ба __eq__-ийн ялгааг харьцуулах нь тооцоолсон утгын хоёр аргыг ойлгох сайн туршилт. Эдгээр бүгд санал бөгөөд дараагийн хичээлүүд үүнийг хийсэн гэж үзэхгүй.
ValueError: mutable default <class ‘list’> for field tags is not allowed: use default_factory. “tags талбарт <class ‘list’> төрлийн өөрчлөгдөж болох анхдагч утга зөвшөөрөгдөхгүй: default_factory хэрэглэ” гэсэн утгатай. dataclass талбарт list, dict, set шууд анхдагч болгон өгөхөд class тодорхойлогдох үед гарна. Шийдэл мессеждээ: field(default_factory=list). Энэ алдаа таныг Хичээл 7.3-ын урхинаас хамгаалж байна.
TypeError: ‘list’ object is not callable. “list объектыг дуудах боломжгүй” гэсэн утгатай. default_factory-д функцийн оронд түүний үр дүнг өгөхөд гарна: field(default_factory=[]) эсвэл field(default_factory=list()). dataclass объект үүсэх бүрт factory-г дуудах гэж оролдох ч list объект дуудагдаж чадахгүй. Алдаа class тодорхойлогдох үед биш, анхны объект үүсгэх үед гарна. Хичээл 5.1-ийн "функц ба түүний дуудлага" ялгаа дахин: factory бол үйлдвэр, түүний бүтээгдэхүүн биш.
dataclasses.FrozenInstanceError: cannot assign to field ‘amount’. “amount талбарт оноох боломжгүй” гэсэн утгатай. frozen dataclass-ийн талбарт оноох гэж оролдоход гарна. Хэрэв энэ санаатай хамгаалалт бол зөв ажиллаж байна: өөрчлөлтийн оронд replace(obj, amount=...)-ээр шинэ объект үүсгэ. Хэрэв __post_init__ дотор гарсан бол Жишээ 3-ын төгсгөлд тайлбарласан тойрох зам эсвэл property.
TypeError: unhashable type: ‘Student’. “Student төрөл hash хийгдэх боломжгүй” гэсэн утгатай. frozen-гүй dataclass-ийг set-д хийх, dict-ийн түлхүүр болгох, lru_cache-тай функцэд өгөх үед гарна. Шийдэл: хэрэв объект утга шинжтэй, үүссэний дараа өөрчлөгдөх шаардлагагүй бол @dataclass(frozen=True). Хэрэв өөрчлөгдөх ёстой бол түүний оронд өөрчлөгдөхгүй ID-г түлхүүр болгон хэрэглэ.
TypeError: non-default argument ‘score’ follows default argument. "Анхдагч утгагүй ‘score’ argument анхдагч утгатай argument-ын дараа байна" гэсэн утгатай. Python-ий шинэ хувилбарууд мессежид өмнөх талбарын нэрийг ч нэмж бичдэг. Анхдагч утгатай талбарын дараа анхдагчгүй талбар бичихэд class тодорхойлогдох үед гарна. Энгийн функцэд def f(a=1, b): зөвшөөрөгдөхгүйтэй ижил дүрэм, учир нь dataclass талбаруудын дарааллаар __init__-ийн параметрүүдийг үүсгэдэг. Шийдэл нь анхдагчгүй талбаруудыг эхэнд нь байрлуулах.
__post_init__ огт ажиллахгүй байх. Мессежгүй алдаа. Нэрийг буруу бичсэн үед гарна: __postinit__, _post_init_, __post_init. dataclass яг __post_init__ нэрийг хайдаг. Олдохгүй бол юу ч дуудахгүй, ямар ч анхааруулгагүй. Шинж тэмдэг нь шалгалт ажиллахгүй байх, тооцоолсон талбар байхгүй байх. Буруу утгаар объект үүсгэж үзээд, алдаа гарах ёстой үед гарч байгаа эсэхийг шалгаарай.
dataclass type hint-тэй талбаруудыг уншаад __init__, __repr__, __eq__-ийг үүсгэдэг. Үүсгэсэн __init__ бидний гараар бичдэг кодтой ойролцоо. Талбарууд объект бүрийн өөрийн attribute болдог, type hint-гүй нэрс жирийн class attribute хэвээр. Өөрчлөгдөж болох анхдагч утгыг dataclass class тодорхойлогдох үед илрүүлж татгалздаг. Түүний оронд field(default_factory=list) нь объект үүсэх бүрт factory-г дуудаж шинэ утга үүсгэдэг. @dataclass(frozen=True) нь объектыг үүссэний дараа өөрчлөгдөхгүй болгож, FrozenInstanceError-оор хамгаалдаг, replace()-ээр шинэ хувилбар үүсгэдэг. Мөн объектыг hash хийгдэх боломжтой болгож, set, dict, lru_cache-д хэрэглэх боломж олгодог. frozen гүехэн тул доторх өгөгдлийг ч өөрчлөгдөхгүй төрлөөр сонгоно. __post_init__ үүсгэсэн __init__-ийн дараа ажиллаж, хэвийн болгох, шалгалт, тооцоолсон талбарт хэрэглэгддэг. field(init=False) талбарыг __init__-ийн параметрээс хасна. classmethod туслах хаалганууд cls(...)-ээр энэ бүх замыг дамждаг.
Ингээд Бүлэг 7 дуусч, class-ийн гүнзгий хэрэгслүүд бидний гарт байна. Дараагийн бүлэг class-уудыг Python-ий бэлэн төрлүүд шиг байгалийн мэт ажилладаг болгоно. Энэ хичээлийн Money-г санаарай: хоёр мөнгөн дүнг нэмэхийн тулд одоо Money(a.amount + b.amount) гэж бичих хэрэгтэй. Дараагийн хичээлд бид operator overloading-тэй танилцаж, a + b гэж шууд бичиж болдог болгоно. Мөн өөр валютын мөнгийг нэмэх гэж оролдоход Python-д "би үүнийг хийж чадахгүй" гэж хэрхэн шударгаар хэлэхийг, NotImplemented гэсэн тусгай утгыг сурна.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.