Ачааллж байна...
Өмнөх хичээлд бид method-ын хоёр дахь төрөл болох classmethod-той танилцсан. Энгийн method эхний argument болгон объектыг, self-ийг хүлээн авдаг бол classmethod class-ийг, cls-ийг хүлээн авдаг. Python-д гурав дахь төрөл бий: staticmethod. Энэ нь эхний argument болгон юу ч хүлээн авдаггүй: self ч биш, cls ч биш. Энэ нь class дотор байрлаж байгаа энгийн функц юм.
Гурван төрөл байгаа нь шинэ асуулт үүсгэнэ: шинэ method бичих бүрдээ аль төрлийг сонгох вэ? Course 2-т бид бүх method-ыг энгийн method хэлбэрээр бичдэг байсан, учир нь өөр сонголт мэдээгүй. Одоо гурван сонголт байгаа тул буруу сонголт хийх боломж ч гарч ирлээ. Буруу сонголт ихэвчлэн алдаа гаргадаггүй ч Хичээл 7.1-ийн cls урхи шиг удамшлын үед чимээгүй асуудал үүсгэж, эсвэл кодыг шаардлагагүй ойлгомжгүй болгодог.
Энэ хичээлийн зорилго хоёр. Нэгдүгээрт, staticmethod-ыг танилцуулж, гурван төрлийг нэг class дээр зэрэгцүүлэн, Python тус бүрт эхний argument болгон юу нэмдгийг trace-ээр харуулна. Хоёрдугаарт, сонголт хийх энгийн, шударга дүрэм гаргана. Шударга гэдэг үг энд чухал: staticmethod бусад хэлэнд, жишээлбэл Java-д, маш түгээмэл байдаг ч Python-д түүний оронд ихэвчлэн модулийн түвшний энгийн функц хэрэглэдэг. Энэ хичээл staticmethod хэзээ үнэхээр хэрэгтэй, хэзээ илүүдэл болохыг тодорхой хэлнэ.
Жижиг компанийн оффисыг төсөөлөөд үзээрэй. Ажилтан бүр өөрийн ширээ, өөрийн файл, өөрийн ажлын даалгавартай. Ажилтан "миний тайланг дуусга" гэсэн ажил хийхдээ өөрийн ширээн дээрх өгөгдлийг ашиглана. Энэ бол энгийн method: тэр тодорхой нэг объектын, self-ийн өгөгдөлтэй ажилладаг.
Оффист хүний нөөцийн хэлтэс бий. Тэр ямар нэг тодорхой ажилтны ширээн дээр ажилладаггүй, компанийн бүхэлд нь төлөөлдөг. Түүний гол ажил бол шинэ ажилтан авах: анкет хүлээн авч, бичиг баримтыг шалгаж, шинэ ажилтныг компанид бүртгэх. Энэ бол classmethod: тэр class-ийг бүхэлд нь мэддэг, шинэ объект үүсгэж чаддаг.
Эцэст нь оффисын тавиур дээр тооны машин ба дүрмийн гарын авлага байна. Тооны машин хэнийх ч биш, ямар нэг ажилтны мэдээлэл ч, компанийн бүртгэл ч хэрэглэдэггүй. Тэр зүгээр л тооцоолно. Гэвч тэр энэ оффист хадгалагддаг, учир нь энд хэрэглэгддэг. Хэрэв түүнийг гудамжны цаад талын хоршооны нийтийн танхимд тавьсан ч адилхан ажиллах байсан. Энэ бол staticmethod: class дотор байрладаг ч class-ийн юуг ч хэрэглэдэггүй хэрэгсэл. Мөн тэр гудамжны цаад тал бол модулийн түвшний функц.
Зүйрлэлийн сүүлийн хэсэгт гол сонголт оршино: тооны машиныг оффисдоо хадгалах уу, нийтийн танхимд тавих уу? Хэрэв зөвхөн энэ оффист хэрэглэгддэг, оффисын ажлын онцлогтой холбоотой бол оффист нь. Хэрэв олон оффис хэрэглэдэг бол нийтийн танхимд нь.
Өмнөх хичээлийн Student class-ийг өргөтгөе. Одоо оноо 0-ээс 100-ийн хооронд байх ёстой гэсэн шалгалт нэмье. Энэ шалгалт __init__-д ч, from_string-д ч хэрэгтэй.
python
class Student:
def __init__(self, name, score):
if not Student.is_valid_score(score):
raise ValueError(f"Оноо 0-100 хооронд байх ёстой, {score} ирлээ")
self.name = name
self.score = score
@classmethod
def from_string(cls, text):
name, score = text.split(",")
return cls(name.strip(), int(score))
@staticmethod
def is_valid_score(value):
return 0 <= value <= 100
def grade(self):
if self.score >= 90:
return "A"
if self.score >= 75:
return "B"
if self.score >= 60:
return "C"
return "F"
def __repr__(self):
return f"{type(self).__name__}({self.name!r}, {self.score})"
s = Student.from_string("Бат, 95")
print(s, s.grade())
print(Student.is_valid_score(105))
Student("Сараа", 120)Student('Бат', 95) A
False
Traceback (most recent call last):
...
ValueError: Оноо 0-100 хооронд байх ёстой, 120 ирлээЭнэ class гурван төрлийг бүгдийг агуулж байна. grade бол энгийн method: self.score-ийг хэрэглэдэг тул тодорхой нэг сурагчийн оноо хэрэгтэй. from_string бол classmethod: шинэ объект үүсгэдэг тул cls хэрэгтэй. is_valid_score бол staticmethod: @staticmethod decorator-тай, эхний argument нь value, self ч биш, cls ч биш. Тэр ердөө тоог шалгадаг: аль сурагчийнх ч биш, Student class-ийн тухай ч юу ч мэдэх шаардлагагүй.
is_valid_score-ийг объектгүйгээр, class-аар дуудсан: Student.is_valid_score(105). Мөн __init__ дотроос түүнийг Student.is_valid_score(score) гэж дуудсан. Энэ дуудлагын хэлбэрт Жишээ 2-т буцаж ирнэ, тэнд илүү сайн хувилбар бий. 120 оноотой Сараа шалгалтыг давж чадаагүй, объект үүсээгүй. from_string ч мөн cls(...)-ээр __init__-ийг дууддаг тул шалгалт автоматаар хэрэглэгдэнэ. Хичээл 7.1-ийн "бүх хаалга нэг коридороор" санаа энд бодит үр шимээ өгч байна.
Trace: Python эхний argument-д юу нэмдэг вэ
Гурван төрлийн жинхэнэ ялгаа нэг асуултад оршино: method дуудагдахад Python эхний argument болгон юу далдуур нэмэх вэ? Python-оос шууд асууя. Method-ыг дуудалгүйгээр, хаалтгүйгээр хэвлэхэд Python түүнийг ямар зүйл болгон "холбосныг" харуулна:
python
s = Student("Бат", 95)
print(s.grade)
print(Student.from_string)
print(Student.is_valid_score)
print(s.is_valid_score)<bound method Student.grade of Student('Бат', 95)>
<bound method Student.from_string of <class '__main__.Student'>>
<function Student.is_valid_score at 0x7f2a1b3c4d60>
<function Student.is_valid_score at 0x7f2a1b3c4d60>Мөр бүрийг уншъя.
s.grade. “bound method” буюу "холбогдсон method", of Student('Бат', 95). Python grade-ийг s объекттой холбосон. Энэ нь grade дуудагдахад s автоматаар self болон орно гэсэн үг. s.grade() бол үнэндээ Student.grade(s).
Student.from_string. Мөн “bound method”, гэвч of <class ‘main.Student’>. Python from_string-ийг объекттой биш, Student class-тай холбосон. Тэгэхээр from_string дуудагдахад Student class автоматаар cls болон орно. Хичээл 7.1-ийн trace-ийн Алхам 1 энэ.
Student.is_valid_score. “bound method” биш, энгийн function. Python юу ч холбоогүй. Дуудлагад та өгсөн argument-ууд л орно.
s.is_valid_score. Объектоор хандсан ч мөн энгийн function, яг ижил хаягтай. staticmethod объектоор ч, class-аар ч хандсан бай, ижил энгийн функц. Python s-ийг нэмэхгүй.
Тэгэхээр гурван төрлийн ялгаа нь “Python эхний argument-д юу нэмдэг вэ” гэсэн асуултын гурван хариулт: объект, class, эсвэл юу ч биш. Decorator-ууд Python-д энэ зан чанарыг хэлдэг: decorator-гүй method объекттой холбогдоно, @classmethod class-тай, @staticmethod юутай ч холбогдохгүй. Хичээл 5.4-т property класс байсныг санаарай: classmethod ба staticmethod ч мөн класс. Тэдгээр нь Хичээл 5.4-т нэрлэсэн descriptor механизмаар ажилладаг бөгөөд энэ механизм энэ сургалтын хүрээнээс гадуур байдаг.
Гурван төрлийг таньсны дараа сонголтын дүрмийг гурван асуултаар томьёолъё. Шинэ method бичих бүрдээ дарааллаар нь асууна.
Асуулт 1: энэ method тодорхой нэг объектын өгөгдлийг хэрэглэх үү? Өөрөөр хэлбэл, self.name, self.score, эсвэл объектын өөр method-ыг хэрэглэх үү? Хэрэв тийм бол энгийн method. Энэ бол хамгийн түгээмэл тохиолдол: method-уудын ихэнх нь энгийн method байдаг бөгөөд байх ёстой.
Асуулт 2: энэ method class-ийг өөрийг нь хэрэглэх үү? Шинэ объект үүсгэх үү, class-ийн өөр classmethod-ыг дуудах уу, эсвэл удамшсан class-д өөрөөр ажиллах ёстой юу? Хэрэв тийм бол classmethod. Хамгийн түгээмэл нь Хичээл 7.1-ийн туслах хаалга.
Асуулт 3: аль нь ч биш бол энэ функц хаана амьдрах ёстой вэ? Хэрэв тэр зөвхөн энэ class-д хэрэглэгддэг, түүний ойлголттой нягт холбоотой бол staticmethod: is_valid_score нь Student-ийн дүрэм, түүнийг Student дотор олох нь зүйн хэрэг. Хэрэв тэр олон class, олон газар хэрэгтэй ерөнхий хэрэгсэл бол модулийн түвшний функц: Хичээл 3.2-ын mongolian_key нь Student-д ч, Teacher-т ч, Course-д ч хэрэгтэй тул ямар нэг class-д хамааруулах шаардлагагүй.
Шударга тэмдэглэл: Python-д гурав дахь асуултын хариулт ихэвчлэн модулийн функц байдаг. Модулийн функц импортлоход хялбар, тестлэхэд хялбар, class-ийн мэдлэг шаарддаггүй. staticmethod-ыг "энэ функц class-ийн өөрийн дүрэм, түүнийг class-аас тусад нь бодох утгагүй" гэсэн тохиолдолд л сонгоно. Хэрэв эргэлзэж байгаа бол модулийн функцээс эхэл.
Жишээ 1: staticmethod-ын жинхэнэ давуу тал — удамшилд дарж бичих
Модулийн функцтэй харьцуулахад staticmethod-ын нэг бодит давуу тал бий: удамшсан class түүнийг дарж бичиж болно. Магистрант оюутнуудын хувьд оноо 60-аас доош байж болохгүй гэсэн илүү хатуу дүрэм хэрэгтэй гэж бодъё:
python
class GraduateStudent(Student):
@staticmethod
def is_valid_score(value):
return 60 <= value <= 100
g = GraduateStudent("Ану", 45)
print(g)GraduateStudent('Ану', 45)Хүлээгээгүй үр дүн: 45 оноотой магистрант үүссэн. GraduateStudent шинэ дүрэм тодорхойлсон ч __init__ түүнийг хэрэглээгүй. Шалтгаан нь Анхны жишээний __init__ дотор: Student.is_valid_score(score). Class-ийн нэр хатуу бичигдсэн тул удамшсан class-аас дуудсан ч Student-ийн хувилбар ажилласан. Энэ бол Хичээл 7.1-ийн cls урхитай яг ижил асуудал, гэхдээ одоо staticmethod дээр.
Шийдэл нь self-ээр дамжуулан дуудах:
python
class Student:
def __init__(self, name, score):
if not self.is_valid_score(score):
raise ValueError(f"Оноо хүлээн зөвшөөрөгдөхгүй: {score}")
self.name = name
self.score = score
@staticmethod
def is_valid_score(value):
return 0 <= value <= 100
def __repr__(self):
return f"{type(self).__name__}({self.name!r}, {self.score})"
class GraduateStudent(Student):
@staticmethod
def is_valid_score(value):
return 60 <= value <= 100
print(Student("Ану", 45))
GraduateStudent("Ану", 45)Student('Ану', 45)
Traceback (most recent call last):
...
ValueError: Оноо хүлээн зөвшөөрөгдөхгүй: 45self.is_valid_score(score) нь Python-д "энэ объектын class-ийн is_valid_score-ийг ол" гэж хэлдэг. GraduateStudent объектын хувьд энэ нь GraduateStudent-ийн хатуу дүрэм. Trace-ийн мэдлэгээр: staticmethod объектоор хандсан ч self-ийг argument болгон нэмдэггүй тул self.is_valid_score(score) нь зөв ажиллана. self энд зөвхөн "аль class-ийн хувилбарыг хайх вэ" гэдгийг шийдэхэд хэрэглэгдсэн. Хэрэв is_valid_score модулийн функц байсан бол удамшсан class түүнийг ингэж дарж бичих боломжгүй байх байсан. Энэ бол staticmethod-ыг сонгох хамгийн хүчтэй шалтгаан.
Эндээс дүрэм: class-ийн method дотроос өөр method-ыг дуудахдаа, тэр staticmethod ч бай, classmethod ч бай, class-ийн нэрийг бүү бич. Энгийн method-оос self-ээр, classmethod-оос cls-ээр дууд.
Жишээ 2: staticmethod биш, classmethod байх ёстой тохиолдол
Заримдаа staticmethod мэт санагдах функц үнэндээ cls хэрэгтэй байдаг. Хамгийн түгээмэл тохиолдол: функц объект үүсгэдэг.
python
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
@staticmethod
def anonymous(score):
return Student("Нэргүй", score)
def __repr__(self):
return f"{type(self).__name__}({self.name!r}, {self.score})"
class GraduateStudent(Student):
pass
print(GraduateStudent.anonymous(80))Student('Нэргүй', 80)anonymous staticmethod-оор бичигдсэн бөгөөд Student-ийн нэр хатуу бичигдсэн. GraduateStudent-ээр дуудахад энгийн Student гарсан. Сонголтын дүрмийн Асуулт 2-ыг санаарай: "шинэ объект үүсгэх үү?" Тийм. Тэгэхээр энэ classmethod байх ёстой:
python
@classmethod
def anonymous(cls, score):
return cls("Нэргүй", score)Одоо GraduateStudent.anonymous(80) нь GraduateStudent объект үүсгэнэ. Объект үүсгэдэг method үргэлж classmethod, хэзээ ч staticmethod биш.
Жишээ 3: self хэрэглэдэггүй энгийн method
Эсрэг тохиолдол: энгийн method бичсэн атлаа тэр self-ийг огт хэрэглэдэггүй.
python
class Report:
def __init__(self, title, rows):
self.title = title
self.rows = rows
def format_amount(self, amount):
return f"{amount:,}₮"
def render(self):
lines = [self.title]
for name, amount in self.rows:
lines.append(f" {name}: {self.format_amount(amount)}")
return "\n".join(lines)
report = Report("Өдрийн борлуулалт", [("Ном", 125000), ("Дэвтэр", 34500)])
print(report.render())Өдрийн борлуулалт
Ном: 125,000₮
Дэвтэр: 34,500₮render нь self.title ба self.rows-ийг хэрэглэдэг тул энгийн method байх нь зөв, Асуулт 1-д тийм. Харин format_amount self параметртэй атлаа түүнийг огт хэрэглэдэггүй: тоог форматлахад тайлангийн гарчиг, мөрүүд хэрэггүй. Асуулт 1: үгүй. Асуулт 2: үгүй. Асуулт 3: энэ функц тайлангаас гадна хэрэгтэй юу? Мөнгө форматлах нь програмын бусад олон газарт хэрэгтэй байх магадлалтай. Үнэндээ Хичээл 4.3-т бид make_money_formatter гэсэн илүү уян хатан хувилбарыг аль хэдийн бичсэн.
Тэгэхээр хамгийн зөв шийдэл нь format_amount-ийг class-аас гаргаж, модулийн функц болгох, эсвэл make_money_formatter-ийг ашиглах. Хэрэв энэ форматлалт тайлангийн өөрийн тусгай дүрэм байсан бол, жишээлбэл тайланд л хэрэглэгддэг тусгай тэмдэглэгээ, staticmethod болгоно. self хэрэглэдэггүй энгийн method бол алдаа биш, ажилладаг, гэхдээ уншигчийг "энэ method объектын өгөгдөлтэй ажилладаг" гэж төөрөгдүүлдэг. Зарим linter ийм method-уудыг илрүүлж, staticmethod эсвэл функц болгохыг санал болгодог.
Жишээ 4: класс бие нь хаалттай орон зай биш
Сүүлийн жишээ Бүлэг 4-ийн LEGB мэдлэгтэй холбоотой нарийн зүйлийг харуулна. Анхны жишээнд __init__ is_valid_score-ийг Student. эсвэл self. угтвартайгаар дуудсан. Хэрэв угтваргүй дуудвал?
python
class Student:
@staticmethod
def is_valid_score(value):
return 0 <= value <= 100
def __init__(self, name, score):
if not is_valid_score(score):
raise ValueError("буруу оноо")
self.name = name
self.score = score
Student("Бат", 95)Traceback (most recent call last):
...
NameError: name 'is_valid_score' is not definedХичээл 4.1-ийн LEGB-ийг санаарай: функц дотор нэр Local, Enclosing, Global, Built-in дарааллаар хайгддаг. Энгийн хүлээлт бол __init__ class-ийн бие дотор тодорхойлогдсон тул class-ийн бие Enclosing түвшин болж, is_valid_score тэндээс олдох байсан. Гэвч Python-д class-ийн бие Enclosing түвшин биш. Энэ бол Python-ий санаатай дизайн: method-ууд class-ийн бусад нэрсийг шууд хардаггүй, заавал self эсвэл class-аар дамжуулан хандах ёстой. Ингэснээр Жишээ 1-ийн удамшлын дарж бичилт ажиллах боломжтой болдог: хэрэв method-ууд class-ийн нэрсийг шууд хардаг байсан бол тэд үргэлж өөрсдийн тодорхойлогдсон class-ийн хувилбарыг харах байсан.
Тэгэхээр method дотроос class-ийн бусад гишүүнд хандах ганц зам нь self эсвэл cls. Python-ий “explicit is better than implicit”, "тодорхой бол далдаас дээр" гэсэн зарчмын нэг илрэл.
Хүсвэл өөрийн Course 2 эсвэл Course 3-ын төслөөс нэг class сонгож, түүний method бүрийг сонголтын дүрмийн гурван асуултаар шалгаж үзээрэй. self хэрэглэдэггүй энгийн method олдох уу? Объект үүсгэдэг staticmethod олдох уу? Сонирхвол Анхны жишээний Student-ийн grade method-ыг staticmethod болгож, оноог argument болгон авдаг болгоод, __init__-ээс self.grade-ийг дуудаж, GraduateStudent-д илүү хатуу үнэлгээний шатлалаар дарж бичиж болно. Мөн print(s.grade), print(Student.grade) хоёрыг харьцуулах нь trace-ийн “bound method” ба “function” хоёрын ялгааг өөрийн нүдээр харах энгийн туршилт. Эдгээр бүгд санал бөгөөд дараагийн хичээлүүд үүнийг хийсэн гэж үзэхгүй.
TypeError: Student.is_valid_score() takes 1 positional argument but 2 were given. “Student.is_valid_score() байрлалын 1 argument авдаг боловч 2 ирлээ” гэсэн утгатай. @staticmethod мөрийг мартсан бөгөөд method-ыг объектоор, эсвэл self-ээр дуудсан үед гарна. Decorator-гүй бол is_valid_score энгийн method болж, Python объектыг эхний argument болгон нэмнэ: таны өгсөн нэг утга дээр нэмээд хоёр. Сонирхолтой нь Student.is_valid_score(95) гэж class-аар дуудвал алдаа гарахгүй, учир нь class-аар дуудахад Python юу ч нэмдэггүй. Тэгэхээр алдаа зөвхөн self-ээр дуудах үед л илэрнэ. “2 were given” гэж нэгээр илүү тоо харагдвал decorator-ыг шалгаарай.
NameError: name ‘self’ is not defined. “self гэдэг нэр тодорхойлогдоогүй” гэсэн утгатай. staticmethod дотор self-ийг хэрэглэх гэж оролдоход гарна. staticmethod self хүлээн авдаггүй тул түүний дотор self гэсэн нэр байхгүй. Хэрэв method объектын өгөгдөл хэрэгтэй бол тэр staticmethod биш, энгийн method байх ёстой: сонголтын дүрмийн Асуулт 1.
NameError: name ‘is_valid_score’ is not defined. “is_valid_score гэдэг нэр тодорхойлогдоогүй” гэсэн утгатай. Жишээ 4-ийн тохиолдол: method дотроос class-ийн өөр гишүүнийг угтваргүйгээр дуудсан. Class-ийн бие Enclosing түвшин биш тул нэр олдохгүй. Шийдэл: энгийн method дотроос self.is_valid_score(...), classmethod дотроос cls.is_valid_score(...).
TypeError: Student.grade() missing 1 required positional argument: ‘self’. “Student.grade()-д шаардлагатай ‘self’ argument дутуу байна” гэсэн утгатай. Энгийн method-ыг объектгүйгээр, class-аар дуудсан үед гарна: Student.grade(). Trace-ийн дагуу class-аар дуудахад Python юу ч нэмэхгүй тул self хоосон үлдэнэ. Шийдэл нь объект үүсгээд түүгээр дуудах: s.grade(). Хэрэв method-ыг объектгүйгээр дуудах шаардлагатай байгаа бол тэр нь өөрөө self хэрэггүй байж магадгүй: staticmethod эсвэл classmethod болгох эсэхийг сонголтын дүрмээр шалга.
Удамшсан class-ийн дүрэм үл тоогдох. Мессежгүй алдаа, Жишээ 1-ийн урхи. Method дотроос staticmethod-ыг class-ийн нэрээр дуудсан тул удамшсан class-ийн дарж бичсэн хувилбар хэрэглэгдэхгүй. Шинж тэмдэг: удамшсан class-д шинэ дүрэм нэмсэн атлаа объектууд хуучин дүрмээр шалгагдах. Шийдэл: self эсвэл cls-ээр дуудах.
Python-д method-ын гурван төрөл бий бөгөөд тэдгээрийн ялгаа нь Python эхний argument-д юу нэмдэгт оршино. Энгийн method объектыг self болгон авдаг, @classmethod class-ийг cls болгон авдаг, @staticmethod юу ч нэмэлтээр авдаггүй, class дотор амьдардаг энгийн функц. Python энэ холболтыг “bound method of объект”, “bound method of class”, “function” гэж харуулдаг. Сонголтын дүрэм гурван асуулттай: объектын өгөгдөл хэрэгтэй бол энгийн method; class хэрэгтэй, ялангуяа объект үүсгэдэг бол classmethod; аль нь ч хэрэггүй бөгөөд зөвхөн энэ class-ийн дүрэм бол staticmethod, олон газарт хэрэгтэй ерөнхий хэрэгсэл бол модулийн функц. Python-д staticmethod Java-аас хамаагүй цөөн хэрэглэгддэг. Түүний бодит давуу тал нь удамшсан class түүнийг дарж бичих боломж бөгөөд энэ нь method-ыг self эсвэл cls-ээр дуудах үед л ажилладаг. Class-ийн бие Enclosing түвшин биш тул method-ууд class-ийн бусад гишүүнд зөвхөн self эсвэл cls-ээр дамжуулан хандана.
Энэ хичээлд class-ийн түвшинд байрладаг нэг зүйлтэй танилцсан: staticmethod функц. Class-ийн түвшинд функц төдийгүй өгөгдөл ч байрлаж чадна: class attribute. Тэр бүх объектод хуваалцагддаг бөгөөд үүнийг зөв хэрэглэвэл хүчирхэг, буруу хэрэглэвэл Python-ий хамгийн хэцүү олддог алдаануудын нэгийг үүсгэдэг. Дараагийн хичээлд бид объектын тоолуурыг хууль ёсны хэрэглээ болгон бүтээж, дараа нь өөрчлөгдөж болох class attribute-ын урхийг санаатайгаар үүсгэн, хуваалцсан өгөгдлийн чимээгүй эвдрэлийг trace-ээр харж, засна.
Бүртгэлтэй болсноор энэ сургалтын бүх хичээлд хандах эрх авна.