Pythonda decoratorlar
Future Dreams
Funksiya nimaligini bilmaydigan ilonshunoslarni avval bu yerga taklif qilaman: Pythonda funksiya
Funksiya - bu ham bir obyekt
Pythonda funksiyalarning dinamik tarzda yaratilishi, o'zgartirilishi, boshqa bir funksiyaga argument qilib berilishi - bu shunchaki ilonshunoslarga xos ajoyib imkoniyatlardan bir tomchi.
def funksiya(a):
print("Bu argument:", a)
funksiya(1)
>>>Bu argument: 1
funksiya.qiymat = 2
funksiya(funksiya.qiymat)
>>>Bu argument: 2
Funksiyaga dinamik holda ham mana shu kabi ancha o'zgarishlar kirita olamiz. Asosiy maqsad - funksiya ham shunchaki bir obyekt ekanligini tushunib olish.
Funksiyani boshqa bir funksiya bilan o'rash mumkin
Deylik, bizda funksiya bor: u sonning kvadratini hisoblasin.
def kvadrat(x):
return x**2
Funksiya shunchaki judayam sodda, lekin biz so'ragan ishni bajarib beradi. BIROQ, funksiyaga son bo'lmagan biror qiymat (masalan, string: "23") berilganda xatolikka duch kelamiz. Keling shu ishni boshqa bir funksiya zimmasiga yuklaymiz. U funksiyalarga berilgan qiymatni songa aylantirib beraversin.
def string2son(f):
def yangi_funksiya(x):
return f(int(x))
return yangi_funksiya
string2son buning ma'nosiga tushunmaganlar uchun: string to son, ya'nikim "stringdan songa" degani (two ni to tarzida o'qiyveramiz, bizga bo'ladi).
4 qator kod. Bir dunyo savol tug'ilgan bo'lishi mumkin sizda. Savollarga o'tishdan oldin bu "o'rovchi" funksiyani ishlatib ko'ramiz.
def kvadrat(x):
return x**2
yangi_funk = strin2son(kvadrat)
print(yangi_funk("5"))
>>>25
Xo'sh, nimalar bo'ldi bu yerda?
Unchalik murakkab jarayon bo'lmadi. Agar tushunmagan bo'lsangiz, sal shoshdingiz, xolos. Keling, birgalikda tushunishga harakat qilamiz.
string2son funksiyamiz avvalo nima uchun xizmat qilyapti? U SHUNCHAKI YANGI FUNKSIYA OBYEKTINI YARATIB BERYAPTI. Ishonmasangiz kodga qaytadan e'tibor bering. Ha, demak, string2son funksiyasi bizga yangi funksiya yaratib beradi, tamom.
Biz o'sha yangi funksiyani shunchaki yangi_funksiya deb nomlab qo'ya qoldik. Bu "x" deb nomlanuvchi argumentni olib, uni int turiga o'girib, "f" deb nomlanuvchi boshqa bir funksiyaga beradi va u hosil qilgan natijani qaytaradi. Demak.
1. string2son o'ziga "f" degan funksiyani argument sifatida oladi.
2. yangi_funksiya deb nomlanuvchi funksiya yaratishga kirishadi.
3. bu yangi_funksiya o'ziga "x" deb nomlanuvchi argumentni oladi.
4. yangi_funksiya o'zidagi argumentni int turiga o'giradi.
5. int ga o'girilgan qiymatni "f" funksiyasiga uzatadi, uning javobini kutadi. "f" natija qaytargach, uni olib bizga uzatadi.
6. yangi_funksiya shunchaki yaratilyapti, u hali chaqirilgani yo'q.
7. string2son funksiyasi shu hosil bo'lgan yangi_funksiya ni bizga qaytaryapti. Biz endi uni chaqirib ishlata olamiz.
Nimadir tushunarsiz bo'ldimi? Tepaga chiqing, 1-raqamga. Qaytadan o'qib chiqing.
Biz kvadrat deb nomlangan funksiyamizni string2son funksiyasiga berdik, u bizga shu funksiyadan foydalanib, qabul qilinuvchi argumentni int turiga o'girib, keyin uni ishlatadigan YANGI BIR FUNKSIYA tayyorlab berdi. Yakunda esa biz yangi funksiyaga "5" ni berdik, natija esa 25. Yana nimadir tushunarsizmi? Boshidan o'qing.
Mana shu o'rovchi funksiyamizni ishlatish jarayonini soddaroq qilishimizam mumkin. Keling avval hozirgi xarob ahvolimizni esga solvolamiz (oldingisidan sal boshqacharoq kod keltiraman):
def kvadrat(x):
return x**2
print(string2son(kvadrat)("5"))
>>>25
Biz bundan oldin mana bunday yozgandik:
yangi_funksiya = string2son(kvadrat)
print(yangi_funksiya("5"))
Umuman, 2 ta kod bir xil vazifa bajaradi. Shunchaki string2son qaytargan yangi funksiyaga birato'la qiymat berib qo'ya qoldik.
Xo'sh, bu bilan kodni sal ixchamlashtirgandek bo'ldik. Hm... Yo'q. U sirayam ixchamlashmadi. Uni endi ixchamlashtiramiz.
@decorator
Python bizga yuqoridagi butun boshli jarayonni mana bunday qilib ixchamlashtirishga imkon beradi:
@string2son
def kvadrat(x):
return x**2
print(kvadrat("5")
>>>25
Bu kodimizdagi @string2son Pythonda decorator (decorate - bezash) deb nomlanadi. Ya'nikim, u "bezaydi". Funksiyani bezaydi. Shunchaki o'rovchi funksiya nomini olamiz, yangi yaratayotgan funksiyamizning shundoqqina tepasidan, boshiga @ belgisini qo'shib yozib qo'yamiz. Tayyor!
Dekorator bilan yana nima qilolamiz?
Juda ko'p narsa. Deylik, "josus" deb nomlangan dekorator yarataylik. Uning vazifasi judayam sodda: funksiya chaqirilishidan oldin va keyin bizga xabar bersin. Hamda, funksiyaga berilayotgan argumentni bizga ko'rsatsin. Demak, boshladik!
def josus(fun):
print("dekorator ishga tushdi")
print("hali funksiya chaqirilmadi")
def yangi(arg):
print("yangi funksiya chaqirilmoqda...")
print("argument:", arg)
natija = fun(arg)
print("funksiya ishini tugatdi")
return natija
print("yangi funksiya tayyor")
return yangi
Josus tayyor. Josusni kvadrat funksiyasiga qo'llab ko'ramiz.
@josus
def kvadrat(x)
return x**2
print(kvadrat(3))
>>>dekorator ishga tushdi
hali funksiya chaqirilmadi
yangi funksiya tayyor
yangi funksiya chaqirilmoqda...
argument: 3
funksiya ishini tugatdi
9
Nimalardir bo'ldi... Tushunarsizmi? Marhamat qilib qaytadan o'qing.
Bu mavzu ko'pchilikka birinchi martadan qiyin tuyuladi. Ikkinchi va uchinchisidayam qiyin. Umuman olganda ko'pchilik uchun bu doim qiyinligicha qoladi. Lekin siz uchun emas. Balki siz uchundir. Bu maqolani o'qibgina dekoratorlar haqida yaxshi tushuna olmaysiz. Maqolani tugatib, kod yozing, yuqoridagi kodlarni yozib, ishlatib ko'ring. Kodni o'zgartiring, ishga tushiring...
Har qanaqa tushunarsiz holat bo'yicha savollarni @python_uz guruhida kutaman (hurmat bilan savol beramiz va shunday javob olamiz).
Bu joyigacha o'qib, yetib keganingizni o'zi bir bayram. Rahmat. Tugadi.