13 Decorators

image.png Գորիս, լուսանկարի հղումը, Հեղինակ՝ Ani Adigyozalyan

Open In Colab (ToDo)

Song reference - ToDo

🎦 Տեսադասեր + լրացուցիչ (ToDo)

ToDo 1. Տեսություն 2025
2. Տեսություն 2023 (ToDo)
3. Գործնական 2025
4. Գործնական 2023 (ToDo)
5. Որոշ տնայինների լուծումներ (ToDo)

Google Forms ToDo

📚 Նյութը

Ընտիր նյութեր 1. https://realpython.com/primer-on-python-decorators/ 2. https://www.youtube.com/watch?v=FsAPt_9Bf3U

Դասի ընթացքում չենք ծածկում արգումենտ ընդունող դեկորատորների թեման, բայց եթե ուզենաք խորանալ՝ 1. https://realpython.com/primer-on-python-decorators/#decorators-with-arguments 2. https://www.youtube.com/watch?v=KlBPCzcQNU8

import os
import time
def ampi_chap_mec_hashvark():
    res = 509**509
    print(res)
ampi_chap_mec_hashvark()
5240240380464278743038995935164729519022960120789397597473156060006733975688834520162022913119498661811536296970894660221944785532882379972180209351818755937686374464831076775129977591118874007277177769232701178035793622110468583105820995869317107888111030339094119730224614498238530470309345955209289046333268659754025697993820321327528576665084160745994968081952548351844292737367510053066902772974755906581497776725352811031547027961751700611549790988723017891603976699459934147329895538758733283682604326997041974565376219471378660212685343149692980644830533948774497337813380050282417785347438886005791032456579750811817794376292526954586878562941564778295439225606084209474874023753593163886560828535643729573265753937810724408756410646424766759354297244156679059800300042977659576867366022741421236217668170444937601286230431841851714743926805728553764281741069894949546084195770081067594880875519903226718645472813449139172639950182022438627082735260374229083680235941700684700688431686035673317719259864047774086086918489617688801234225254582058990118862064002327820251223938972603639481176531425559740319585419825981843376278277904788218475398662138678271677090801489578564194008987003188863738562864947909718108590545720841315647311798913504045448587075816910272902834164709150355355797010877441039812954215946958352860866270491057877162292684106820265944067453994989
def urish_erkar_func():
    print("zzzzzzzzz")
    time.sleep(1)
urish_erkar_func()
zzzzzzzzz

Ինչ եթե հիմա ուզում ենք հիմա նենց անենք որ ֆունցկիացները նաև վերադարձնեն թե ինչքան ժամանակում են աշխատել

def ampi_chap_mec_hashvark():
    print("starting")
    st = time.perf_counter()

    res = 509**509
    print(res)

    duration = time.perf_counter() - st
    print("done", duration)
ampi_chap_mec_hashvark()
starting
5240240380464278743038995935164729519022960120789397597473156060006733975688834520162022913119498661811536296970894660221944785532882379972180209351818755937686374464831076775129977591118874007277177769232701178035793622110468583105820995869317107888111030339094119730224614498238530470309345955209289046333268659754025697993820321327528576665084160745994968081952548351844292737367510053066902772974755906581497776725352811031547027961751700611549790988723017891603976699459934147329895538758733283682604326997041974565376219471378660212685343149692980644830533948774497337813380050282417785347438886005791032456579750811817794376292526954586878562941564778295439225606084209474874023753593163886560828535643729573265753937810724408756410646424766759354297244156679059800300042977659576867366022741421236217668170444937601286230431841851714743926805728553764281741069894949546084195770081067594880875519903226718645472813449139172639950182022438627082735260374229083680235941700684700688431686035673317719259864047774086086918489617688801234225254582058990118862064002327820251223938972603639481176531425559740319585419825981843376278277904788218475398662138678271677090801489578564194008987003188863738562864947909718108590545720841315647311798913504045448587075816910272902834164709150355355797010877441039812954215946958352860866270491057877162292684106820265944067453994989
done 5.000003147870302e-05
def urish_erkar_func():
    print("starting")
    st = time.perf_counter()

    print("zzzzzzzzzzzzz")
    time.sleep(1)

    duration = time.perf_counter() - st
    print("done", duration)

def ampi_chap_mec_hashvark():
    print("starting")
    st = time.perf_counter()

    res = 509**509
    print(res)

    duration = time.perf_counter() - st
    print("done", duration)
def urish_erkar_func():
    print("starting")
    st = time.perf_counter()

    print("zzzzzzzzzzzzz")
    time.sleep(1)

    duration = time.perf_counter() - st
    print("done", duration)
    
urish_erkar_func()
starting
zzzzzzzzzzzzz
done 1.0028494999860413

Կրկնվող կոդը նշանա որ գուցե ինչ-որ լավ բան կա որ չենք օգտագործում մենք

Դիմավորեք ․․․․․․․․․․․․․ դեկորատորներ

def urish_erkar_func():
    print("zzzzzzzzz")
    time.sleep(1)
    
def ampi_chap_mec_hashvark():
    res = 509**509
    print(res)
func = urish_erkar_func 

print("starting")
st = time.perf_counter()

func()

duration = time.perf_counter() - st
print("done", duration)
starting
zzzzzzzzz
done 1.0062951000290923
print(ampi_chap_mec_hashvark)
print(func)
<function ampi_chap_mec_hashvark at 0x000001305FB7CD30>
func = ampi_chap_mec_hashvark

def nor_func():
    print("starting")
    st = time.perf_counter()

    func()

    duration = time.perf_counter() - st
    print("done", duration)

Հիշեցում - first class object

ֆունցկաիները կոչվում են First-Class Objectներ, ինչը նշանակումա որ իրանց կարանք որպես արգումենտ տանք ուրիշ ֆունկցիաներին, ուրիշ ֆունկցիաները կարան վերադարձնեն ֆունկցիաներ, intի նման ասենք

def ispanakan(anun):
    return f"Բարև {anun}իտո"

def dinozavrakan(anun):
    return f"Բարև {anun}ազավռ"

def barevel(anun, specific_barev):
    return specific_barev(anun)

anun = 'Հայկ'
print(barevel(anun, dinozavrakan))
Բարև Հայկազավռ
def timer(func):
    def stronger_func(a=3, b=4):
        print("starting")
        st = time.perf_counter()
        
        func(a=3, b=4)
        
        
        duration = time.perf_counter() - st
        print("done", duration)
    
    return stronger_func
ampi_chap_mec_hashvark = timer(ampi_chap_mec_hashvark)
ampi_chap_mec_hashvark()
starting
5240240380464278743038995935164729519022960120789397597473156060006733975688834520162022913119498661811536296970894660221944785532882379972180209351818755937686374464831076775129977591118874007277177769232701178035793622110468583105820995869317107888111030339094119730224614498238530470309345955209289046333268659754025697993820321327528576665084160745994968081952548351844292737367510053066902772974755906581497776725352811031547027961751700611549790988723017891603976699459934147329895538758733283682604326997041974565376219471378660212685343149692980644830533948774497337813380050282417785347438886005791032456579750811817794376292526954586878562941564778295439225606084209474874023753593163886560828535643729573265753937810724408756410646424766759354297244156679059800300042977659576867366022741421236217668170444937601286230431841851714743926805728553764281741069894949546084195770081067594880875519903226718645472813449139172639950182022438627082735260374229083680235941700684700688431686035673317719259864047774086086918489617688801234225254582058990118862064002327820251223938972603639481176531425559740319585419825981843376278277904788218475398662138678271677090801489578564194008987003188863738562864947909718108590545720841315647311798913504045448587075816910272902834164709150355355797010877441039812954215946958352860866270491057877162292684106820265944067453994989
done 4.5199994929134846e-05
@timer
def urish_erkar_func():
    print("zzzzzzzzz")
    time.sleep(1)

@timer
def ampi_chap_mec_hashvark():
    res = 509**509
    print(res)
timer(ampi_chap_mec_hashvark)()
starting
5240240380464278743038995935164729519022960120789397597473156060006733975688834520162022913119498661811536296970894660221944785532882379972180209351818755937686374464831076775129977591118874007277177769232701178035793622110468583105820995869317107888111030339094119730224614498238530470309345955209289046333268659754025697993820321327528576665084160745994968081952548351844292737367510053066902772974755906581497776725352811031547027961751700611549790988723017891603976699459934147329895538758733283682604326997041974565376219471378660212685343149692980644830533948774497337813380050282417785347438886005791032456579750811817794376292526954586878562941564778295439225606084209474874023753593163886560828535643729573265753937810724408756410646424766759354297244156679059800300042977659576867366022741421236217668170444937601286230431841851714743926805728553764281741069894949546084195770081067594880875519903226718645472813449139172639950182022438627082735260374229083680235941700684700688431686035673317719259864047774086086918489617688801234225254582058990118862064002327820251223938972603639481176531425559740319585419825981843376278277904788218475398662138678271677090801489578564194008987003188863738562864947909718108590545720841315647311798913504045448587075816910272902834164709150355355797010877441039812954215946958352860866270491057877162292684106820265944067453994989
done 5.640002200379968e-05
ampi_chap_mec_hashvark = timer(ampi_chap_mec_hashvark)
# urish_erkar_func()

ampi_chap_mec_hashvark()
5240240380464278743038995935164729519022960120789397597473156060006733975688834520162022913119498661811536296970894660221944785532882379972180209351818755937686374464831076775129977591118874007277177769232701178035793622110468583105820995869317107888111030339094119730224614498238530470309345955209289046333268659754025697993820321327528576665084160745994968081952548351844292737367510053066902772974755906581497776725352811031547027961751700611549790988723017891603976699459934147329895538758733283682604326997041974565376219471378660212685343149692980644830533948774497337813380050282417785347438886005791032456579750811817794376292526954586878562941564778295439225606084209474874023753593163886560828535643729573265753937810724408756410646424766759354297244156679059800300042977659576867366022741421236217668170444937601286230431841851714743926805728553764281741069894949546084195770081067594880875519903226718645472813449139172639950182022438627082735260374229083680235941700684700688431686035673317719259864047774086086918489617688801234225254582058990118862064002327820251223938972603639481176531425559740319585419825981843376278277904788218475398662138678271677090801489578564194008987003188863738562864947909718108590545720841315647311798913504045448587075816910272902834164709150355355797010877441039812954215946958352860866270491057877162292684106820265944067453994989
timer(ampi_chap_mec_hashvark)
timer(urish_erkar_func)
starting
5240240380464278743038995935164729519022960120789397597473156060006733975688834520162022913119498661811536296970894660221944785532882379972180209351818755937686374464831076775129977591118874007277177769232701178035793622110468583105820995869317107888111030339094119730224614498238530470309345955209289046333268659754025697993820321327528576665084160745994968081952548351844292737367510053066902772974755906581497776725352811031547027961751700611549790988723017891603976699459934147329895538758733283682604326997041974565376219471378660212685343149692980644830533948774497337813380050282417785347438886005791032456579750811817794376292526954586878562941564778295439225606084209474874023753593163886560828535643729573265753937810724408756410646424766759354297244156679059800300042977659576867366022741421236217668170444937601286230431841851714743926805728553764281741069894949546084195770081067594880875519903226718645472813449139172639950182022438627082735260374229083680235941700684700688431686035673317719259864047774086086918489617688801234225254582058990118862064002327820251223938972603639481176531425559740319585419825981843376278277904788218475398662138678271677090801489578564194008987003188863738562864947909718108590545720841315647311798913504045448587075816910272902834164709150355355797010877441039812954215946958352860866270491057877162292684106820265944067453994989
done 7.989000005181879e-05
starting
zzzzzzzzz
done 1.0012614970000868

արգումետներով ու վերադարձով ֆունկցիաներ

def divide(x, y):
    return x / y

def multiply(x, y):
    return x * y
print(divide(22, 7))
print(multiply(10.5, 11.509))
3.142857142857143
120.84450000000001
def divide(x, y):
    return_value = x / y
    
    return round(return_value, 2)

def multiply(x, y):
    return_value = x * y
    
    return round(return_value, 2)
print(divide(22, 7))
print(multiply(10.5, 11.509))
3.14
120.84

եկեք բայց դեկորատորներով անենք

def rounder(func):
    def wrapper(x, y): # գրկող
        res = func(x, y)
        return round(res, 2)
    return wrapper
@rounder
def divide(x, y):
    return x / y

@rounder
def multiply(x, y):
    return x * y
print(divide(22, 7))
print(multiply(10.5, 11.509))
3.14
120.84

Կարանք նաև timer ավելացնենք

@timer
@rounder
def divide(x, y):
    return x / y

# new_func = timer(rounder(divide, 2))

@timer
@rounder
def multiply(x, y):
    return x * y
print(divide(22, 7))
print(multiply(10.5, 11.509))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [52], in <cell line: 1>()
----> 1 print(divide(22, 7))
      2 print(multiply(10.5, 11.509))

TypeError: timer.<locals>.stronger_func() takes 0 positional arguments but 2 were given
def timer(func):
    def nor_func(*args, **kwargs):
        print("starting")
        st = time.perf_counter()
        
        res = func(*args, **kwargs)
        duration = time.perf_counter() - st
        
        print("done")
        print(duration)
        return res

    return nor_func
def rounder(func):
    def wrapper(*args, **kwargs): # գրկող
        res = func(*args, **kwargs)
        return round(res, 2)
    return wrapper
@timer
@rounder
def divide(x, y):
    return x / y

@timer
@rounder
def multiply(x, y):
    return x * y

# timer(rounder(multiply))
print(divide(22, 7))
starting
done
1.4099990949034691e-05
3.14
print(divide(22, 7))

Էլի օրինակներ

Երկու անգամ

def erku_angam(func):
    def nor_func(*args, **kwargs):
        print("arajin angam")
        func(*args, **kwargs)
        
        print("erku angam")
        func(*args, **kwargs)
    return nor_func
@erku_angam
def divide(x, y):
    print(x / y)

divide(3,4)
arajin angam
0.75
erku angam
0.75

ֆունկցիայի դանդաղացուցիչ

def mi_vrazi(func):
    def wrapper_func(*args, **kwargs):
        time.sleep(1)
        return func(*args, **kwargs)
    return wrapper_func
def scrape(url):
    print(f"քաշեցի {url}ի տվյալները")
urls = ['https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/', 'https://www.youtube.com/watch?v=8DYyjqpZRlQ'] * 3

for url in urls:
    scrape(url)
քաշեցի https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/ի տվյալները
քաշեցի https://www.youtube.com/watch?v=8DYyjqpZRlQի տվյալները
քաշեցի https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/ի տվյալները
քաշեցի https://www.youtube.com/watch?v=8DYyjqpZRlQի տվյալները
քաշեցի https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/ի տվյալները
քաշեցի https://www.youtube.com/watch?v=8DYyjqpZRlQի տվյալները
@mi_vrazi
def scrape(url):
    print(f"քաշեցի {url}ի տվյալները")
urls = ['https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/', 'https://www.youtube.com/watch?v=8DYyjqpZRlQ'] * 3

for url in urls:
    scrape(url)
քաշեցի https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/ի տվյալները
քաշեցի https://www.youtube.com/watch?v=8DYyjqpZRlQի տվյալները
քաշեցի https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/ի տվյալները
քաշեցի https://www.youtube.com/watch?v=8DYyjqpZRlQի տվյալները
քաշեցի https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/ի տվյալները
քաշեցի https://www.youtube.com/watch?v=8DYyjqpZRlQի տվյալները

debuger

from datetime import datetime

def debug(func):
    def wrapper(*args, **kwargs):
        print(f"մուտքում ստացել եմ {args} և {kwargs} արգումենտները")
        print(f"Սկսելու ժամանակը {datetime.now().strftime('%H:%M:%S')}")
        st = time.perf_counter()
        
        res = func(*args, **kwargs)
        
        end = time.perf_counter()
        print(f"ծրագիրը աշխատեց {round(end-st, 2)} վարկյանում")
        print(f"ծրագիրը վերադարձրեց՝ {res}\n")
        return res
    return wrapper

@debug
@mi_vrazi
def scrape(url):
    print(f"քաշեցի {url}ի տվյալները")
urls = ['https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/', 'https://www.youtube.com/watch?v=8DYyjqpZRlQ'] * 3

for url in urls:
    scrape(url)
մուտքում ստացել եմ ('https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/',) և {} արգումենտները
Սկսելու ժամանակը 09:32:55
քաշեցի https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/ի տվյալները
ծրագիրը աշխատեց 1.01 վարկյանում
ծրագիրը վերադարձրեց՝ None

մուտքում ստացել եմ ('https://www.youtube.com/watch?v=8DYyjqpZRlQ',) և {} արգումենտները
Սկսելու ժամանակը 09:32:56
քաշեցի https://www.youtube.com/watch?v=8DYyjqpZRlQի տվյալները
ծրագիրը աշխատեց 1.0 վարկյանում
ծրագիրը վերադարձրեց՝ None

մուտքում ստացել եմ ('https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/',) և {} արգումենտները
Սկսելու ժամանակը 09:32:57
քաշեցի https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/ի տվյալները
ծրագիրը աշխատեց 1.01 վարկյանում
ծրագիրը վերադարձրեց՝ None

մուտքում ստացել եմ ('https://www.youtube.com/watch?v=8DYyjqpZRlQ',) և {} արգումենտները
Սկսելու ժամանակը 09:32:58
քաշեցի https://www.youtube.com/watch?v=8DYyjqpZRlQի տվյալները
ծրագիրը աշխատեց 1.02 վարկյանում
ծրագիրը վերադարձրեց՝ None

մուտքում ստացել եմ ('https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/',) և {} արգումենտները
Սկսելու ժամանակը 09:32:59
քաշեցի https://www.instructables.com/Basic-Steps-of-How-to-Make-Cheese/ի տվյալները
ծրագիրը աշխատեց 1.0 վարկյանում
ծրագիրը վերադարձրեց՝ None

մուտքում ստացել եմ ('https://www.youtube.com/watch?v=8DYyjqpZRlQ',) և {} արգումենտները
Սկսելու ժամանակը 09:33:00
քաշեցի https://www.youtube.com/watch?v=8DYyjqpZRlQի տվյալները
ծրագիրը աշխատեց 1.01 վարկյանում
ծրագիրը վերադարձրեց՝ None

Functools example

from functools import lru_cache # Least Recently Used

def gcd(a, b): # greatest common divisor
    time.sleep(1)
    
    while b != 0: # էվկիդլեսի ալգորիթմ
        a, b = b, a % b
    return a
print(gcd(10, 15))
5
%%time
print(gcd(11_509_000_000, 11_509_000_0001))
1
CPU times: total: 0 ns
Wall time: 1 s
from functools import lru_cache

@lru_cache
def gcd(a, b):
    time.sleep(1)
    while b != 0:
        a, b = b, a % b
    return a
%%time
print(gcd(11_509_000_000, 11_509_000_0001))
1
CPU times: total: 0 ns
Wall time: 1.01 s
%%time
print(gcd(11_509_000_000, 11_509_000_0001))
1
CPU times: total: 0 ns
Wall time: 1.51 ms
%%time
print(gcd(11_509_000_001, 11_509_000_002))
1
CPU times: total: 0 ns
Wall time: 0 ns

Հետագայում կօգտագործենք՝

from abc import abstractmethod

class A:
    @abstractmethod
    def method(a)
    
    @staticmethod
    def method(a)

Արգումենտ ընդունող դեկորատորներ

  1. https://realpython.com/primer-on-python-decorators/#decorators-with-arguments
  2. https://www.youtube.com/watch?v=KlBPCzcQNU8
@rounder(4) 
def divide()

@rounder(2)

🏡Տնային

  • lru_cache - ձեռքով գրել
  • դեկորատոր սարքել որ ֆունկցիաների մուտքերը կվերցնի ու կստուգի որ int/float լինեն ու ոչ բացասական, եթե տենց չի՝ exception-ներ raise կանի

🎲 13

Flag Counter