Python / Decorator үндэс

Decorator үндэс

FastAPI, Flask зэрэг framework ашиглахад @app.get("/") гэх мэт тэмдэглэгээ харсан байх. Энэ нь decorator юм. Decorator нь функцийг өөр функцэд "боож", нэмэлт зан байдал оруулдаг хэрэгсэл. Эхлэгчид ойлгоход бага хугацаа шаардагдах боловч суурийг сурвал маш хүчирхэг болно.

Функц нь объект

Python-д функц нь object — хувьсагчид хадгалж, өөр функцэд дамжуулж болно. Энэ нь decorator-ийн үндэс суурь.

python
def мэндлэх():
    print("Сайн уу!")

хийх = мэндлэх       # функцийг хувьсагчид хадгалав
хийх()               # Сайн уу!

def ажиллуул(функц):
    print("Эхлэж байна...")
    функц()
    print("Дууслаа.")

ажиллуул(мэндлэх)
# Эхлэж байна...
# Сайн уу!
# Дууслаа.

Decorator хэрхэн ажилладаг

Decorator нь функцийг аргумент болгон авч, шинэ функц буцаадаг функц юм.

python
def бүртгэгч(функц):
    def боодол(*args, **kwargs):
        print(f"→ {функц.__name__} дуудагдлаа")
        үр_дүн = функц(*args, **kwargs)
        print(f"← {функц.__name__} дууслаа")
        return үр_дүн
    return боодол

def нэмэх(а, б):
    return а + б

нэмэх = бүртгэгч(нэмэх)   # гар аргаар decorator хэрэглэх
print(нэмэх(3, 5))
# → нэмэх дуудагдлаа
# ← нэмэх дууслаа
# 8

@ тэмдэгт — decorator бичих хялбар арга

нэмэх = бүртгэгч(нэмэх) гэж бичихийн оронд @ ашиглана:

python
def бүртгэгч(функц):
    def боодол(*args, **kwargs):
        print(f"→ {функц.__name__} дуудагдлаа")
        үр_дүн = функц(*args, **kwargs)
        print(f"← {функц.__name__} дууслаа")
        return үр_дүн
    return боодол

@бүртгэгч
def мэндлэх(нэр):
    print(f"Сайн уу, {нэр}!")

мэндлэх("Болд")
# → мэндлэх дуудагдлаа
# Сайн уу, Болд!
# ← мэндлэх дууслаа

@бүртгэгч нь мэндлэх = бүртгэгч(мэндлэх) гэсэнтэй яг адилхан.

Практик decorator — хугацаа хэмжих

Дараах decorator нь ямар ч функцийн гүйцэтгэх хугацааг хэмжинэ:

python
import time

def хугацаа_хэмжих(функц):
    def боодол(*args, **kwargs):
        эхлэл = time.time()
        үр_дүн = функц(*args, **kwargs)
        өнгөрсөн = time.time() - эхлэл
        print(f"{функц.__name__}: {өнгөрсөн:.4f} секунд")
        return үр_дүн
    return боодол

@хугацаа_хэмжих
def удаан_функц():
    time.sleep(1)
    return "дууслаа"

удаан_функц()
# удаан_функц: 1.0012 секунд

Олон decorator давхарлах

Нэг функцэд хэд хэдэн decorator хэрэглэж болно — доороос дээш дарааллаар хэрэглэгдэнэ:

python
@бүртгэгч
@хугацаа_хэмжих
def тооцоолох():
    return sum(range(1_000_000))

тооцоолох()
# Эхлэж → хугацаа → функц → хугацаа → дуусав гэсэн дараалалтай

Decorator нь Python-д маш өргөн хэрэглэгддэг — FastAPI-д route тодорхойлох, @property, @staticmethod, @classmethod зэрэг нь бүгд decorator юм.

Дараагийн хичээлд:

Context Manager (with statement) — файл, сүлжээ гэх мэт нөөцийг аюулгүй нээж хаах механизмыг сурна.