Yopilishlar (Closures) bilan tanishish
Python closure (yopilish) — tashqi funksiya yopilgandan keyin ham bizga uning o'zgaruvchilariga murojaat qilish imkonini beruvchi ichma-ich funksiya.
Closure haqida o'rganishdan oldin, keling avval Pythonda ichma-ich funksiyalar tushunchasini takrorlaymiz.
Pythonda, biz boshqa funksiya ichida funksiya yaratishimiz mumkin. Bu ichma-ich funksiya (nested function) deb ataladi. Masalan,
def greet(name):
# ichki funksiya
def display_name():
print("Hi", name)
# ichki funksiyani chaqirish
display_name()
# tashqi funksiyani chaqirish
greet("John")
# Natija: Hi John
Yuqoridagi misolda, biz display_name() funksiyasini greet() funksiyasi ichida aniqladik.
Bu yerda, display_name() — ichma-ich funksiya. Ichma-ich funksiya oddiy funksiyaga o'xshab ishlaydi. U greet() funksiyasi ichida display_name() chaqirilganda bajariladi.
Muhokama qilganimizdek, closure — tashqi funksiya yopilgandan keyin ham bizga uning o'zgaruvchilariga murojaat qilishga yordam beruvchi ichma-ich funksiya. Masalan,
def greet():
# ichki funksiyadan tashqarida aniqlangan o'zgaruvchi
name = "John"
# ichma-ich anonim funksiyani qaytarish
return lambda: "Hi " + name
# tashqi funksiyani chaqirish
message = greet()
# ichki funksiyani chaqirish
print(message())
# Natija: Hi John
Yuqoridagi misolda, biz ichma-ich anonim funksiyani qaytaruvchi greet() nomli funksiya yaratdik.
Bu yerda, tashqi funksiyani chaqirganimizda,
message = greet()
Qaytarilgan funksiya endi message o'zgaruvchisiga beriladi.
Shu paytda, tashqi funksiyaning bajarilishi tugagan, shuning uchun name o'zgaruvchisi yo'q qilinishi kerak. Biroq, biz anonim funksiyani
print(message())
yordamida chaqirganimizda, biz tashqi funksiyaning name o'zgaruvchisiga murojaat qila olamiz.
Bu mumkin, chunki ichma-ich funksiya endi closure sifatida ishlaydi, u tashqi funksiya bajarilib bo'lgandan keyin ham tashqi ko'lam o'zgaruvchisini o'zining ko'lami ichida yopib qo'yadi.
Bu tushunchani aniqlashtirish uchun yana bir misolni ko'ramiz.
Misol: Python closure yordamida toq sonlarni chop etish
def calculate():
num = 1
def inner_func():
nonlocal num
num += 2
return num
return inner_func
# tashqi funksiyani chaqirish
odd = calculate()
# ichki funksiyani chaqirish
print(odd())
print(odd())
print(odd())
# tashqi funksiyani yana chaqirish
odd2 = calculate()
print(odd2())
Natija
3
5
7
3
Yuqoridagi misolda,
odd = calculate()
Bu kod calculate() tashqi funksiyasini bajaradi va toq songa closure'ni qaytaradi.
Shuning uchun biz tashqi funksiya tugagandan keyin ham calculate()ning num o'zgaruvchisiga murojaat qila olamiz.
Yana, biz tashqi funksiyani
odd2 = calculate()
yordamida chaqirganimizda, yangi closure qaytariladi. Shuning uchun, odd2()ni chaqirganimizda yana 3 ni olamiz.
Xo'sh, closure'lar nima uchun foydali?
Closure'lar global qiymatlardan qochish va ma'lumotni yashirish (data hiding) uchun ishlatilishi mumkin va bitta yoki bir nechta metodli oddiy holatlar uchun nafis yechim bo'lishi mumkin.
Biroq, ko'plab atribut va metodlarga ega kattaroq holatlar uchun, klass implementatsiyasi ko'proq mos bo'lishi mumkin.
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
# 3ning ko'paytiruvchisi
times3 = make_multiplier_of(3)
# 5ning ko'paytiruvchisi
times5 = make_multiplier_of(5)
# Natija: 27
print(times3(9))
# Natija: 15
print(times5(3))
# Natija: 30
print(times5(times3(2)))
Python Decorators ham closure'lardan keng foydalanadi.
Yakuniy so'z sifatida, closure funksiyasida yopib qo'yilgan qiymatlarni topish mumkinligini ta'kidlab o'tish yaxshi bo'lardi.
Barcha funksiya obyektlari, agar u closure funksiyasi bo'lsa, cell obyektlarining kortejini qaytaruvchi __closure__ atributiga ega.
Yuqoridagi misolga murojaat qilsak, biz times3 va times5 closure funksiyalari ekanligini bilamiz.