17-bo‘lim

Ilg'or imkoniyatlar

Generatorlar, iteratorlar, dekoratorlar, kontekst menejerlar va comprehension'larning kengaytirilgan shakllari.

🕑 13 daqiqa o‘qish 📄 404 so‘z 👁 5 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Comprehension - to'liq ko'rinish
  2. Ichma-ich comprehension
  3. Generatorlar
  4. yield bilan generator funksiyasi
  5. Amaliy foyda: katta fayllarni o'qish
  6. Iteratorlar
  7. Dekoratorlar
  8. Foydali dekorator misollari
  9. Tayyor dekoratorlar
  10. @staticmethod va @classmethod
  11. Kontekst menejerlar
  12. itertools - kuchli vositalar
  13. Xulosa

Bu bo'limdagi vositalar Python'ni boshqa tillardan ajratib turadi. Ular kodni qisqartiradi va xotira sarfini keskin kamaytiradi.

Comprehension - to'liq ko'rinish #

7-bo'limda ro'yxat generatorlari bilan tanishgandik. Endi to'liq imkoniyatlarini ko'ramiz.

Python
sonlar = range(1, 11)

# Ro'yxat
kvadratlar = [son ** 2 for son in sonlar]

# Shart bilan filtrlash
juftlar = [son for son in sonlar if son % 2 == 0]

# Shartli qiymat (ternar)
belgilar = ["juft" if son % 2 == 0 else "toq" for son in sonlar]

# To'plam - takrorlar yo'qoladi
qoldiqlar = {son % 3 for son in sonlar}

# Lug'at
kublar = {son: son ** 3 for son in range(1, 6)}

print(kvadratlar)
print(juftlar)
print(belgilar[:4])
print(qoldiqlar)
print(kublar)
Natija
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
[2, 4, 6, 8, 10]
['toq', 'juft', 'toq', 'juft']
{0, 1, 2}
{1: 1, 2: 8, 3: 27, 4: 64, 5: 125}

Ichma-ich comprehension #

Python
# Ikki o'lchamli jadvalni yassilash
jadval = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
yassi = [element for qator in jadval for element in qator]
print(yassi)

# Ko'paytirish jadvali
kopaytirish = [[satr * ustun for ustun in range(1, 6)] for satr in range(1, 6)]
for qator in kopaytirish:
    print(qator)
Natija
[1, 2, 3, 4, 5, 6, 7, 8, 9]
[1, 2, 3, 4, 5]
[2, 4, 6, 8, 10]
[3, 6, 9, 12, 15]
[4, 8, 12, 16, 20]
[5, 10, 15, 20, 25]

Generatorlar #

Generator ro'yxatga o'xshaydi, lekin elementlarni oldindan hisoblamaydi - har birini so'ralganda hosil qiladi.

Ro'yxat: hammasi xotirada 1 2 3 4 5 ... 1 000 000 element = ~40 MB Generator: bittasi xotirada 3 o'tdi keyin 1 000 000 element = ~200 bayt
Generator xotirada faqat joriy elementni saqlaydi
Python
import sys

royxat = [son ** 2 for son in range(1_000_000)]      # kvadrat qavs
generator = (son ** 2 for son in range(1_000_000))   # dumaloq qavs

print(f"Ro'yxat:   {sys.getsizeof(royxat):>10,} bayt")
print(f"Generator: {sys.getsizeof(generator):>10,} bayt")
Natija
Ro'yxat:    8,448,728 bayt
Generator:        192 bayt

yield bilan generator funksiyasi #

Python
def fibonachchi(nechta):
    """Fibonachchi ketma-ketligini birma-bir hosil qiladi."""
    oldingi, joriy = 0, 1
    for _ in range(nechta):
        yield oldingi
        oldingi, joriy = joriy, oldingi + joriy


for son in fibonachchi(10):
    print(son, end=" ")
print()

# Ro'yxatga aylantirish ham mumkin
print(list(fibonachchi(15)))
Natija
0 1 1 2 3 5 8 13 21 34 
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
return va yield farqi

return funksiyani tugatadi. yield esa qiymatni qaytaradi va funksiyani to'xtatib turadi - keyingi so'rovda o'sha joydan davom etadi. Barcha lokal o'zgaruvchilar saqlanib qoladi.

Amaliy foyda: katta fayllarni o'qish #

Python
def log_satrlari(yol, kalit_soz):
    """Katta log faylidan faqat kerakli satrlarni birma-bir qaytaradi."""
    with open(yol, "r", encoding="utf-8") as fayl:
        for raqam, satr in enumerate(fayl, start=1):
            if kalit_soz in satr:
                yield raqam, satr.strip()


# 10 GB li faylni ham xotirani to'ldirmasdan o'qiydi
for raqam, satr in log_satrlari("xatolar.log", "ERROR"):
    print(f"{raqam:>5}: {satr}")
Natija
    2: 2026-09-08 14:42:03 [ERROR] Nolga bo'lishga urinish: 10 / 0
   17: 2026-09-08 14:51:20 [ERROR] Fayl topilmadi: hisobot.csv

Iteratorlar #

Generator - iterator protokolining oddiy shakli. Protokolni o'zingiz ham amalga oshirishingiz mumkin:

Python
class TeskariSanoq:
    """Berilgan sondan nolgacha teskari sanaydi."""

    def __init__(self, boshlanish):
        self.joriy = boshlanish

    def __iter__(self):
        return self

    def __next__(self):
        if self.joriy <= 0:
            raise StopIteration
        self.joriy -= 1
        return self.joriy + 1


for son in TeskariSanoq(5):
    print(son, end=" ")
print("Start!")
Natija
5 4 3 2 1 Start!

Dekoratorlar #

Dekorator - funksiyani o'zgartirmasdan unga qo'shimcha xatti-harakat qo'shadigan funksiya.

Python
import time
from functools import wraps


def vaqtni_olcha(funksiya):
    """Funksiya bajarilish vaqtini o'lchaydi."""

    @wraps(funksiya)
    def orab_oluvchi(*args, **kwargs):
        boshlanish = time.perf_counter()
        natija = funksiya(*args, **kwargs)
        davomiylik = time.perf_counter() - boshlanish
        print(f"  [{funksiya.__name__}] {davomiylik:.4f} soniya")
        return natija

    return orab_oluvchi


@vaqtni_olcha
def katta_yigindi(chegara):
    """Berilgan chegaragacha bo'lgan sonlar yig'indisi."""
    return sum(range(chegara))


natija = katta_yigindi(5_000_000)
print(f"Natija: {natija:,}")
Natija
  [katta_yigindi] 0.1284 soniya
Natija: 12,499,997,500,000
@wraps nima uchun kerak?

Dekoratorsiz o'ralgan funksiyaning __name__ va docstring'i yo'qoladi - u orab_oluvchi bo'lib ko'rinadi. functools.wraps asl ma'lumotni saqlab qoladi. Dekorator yozayotganda uni doim qo'shing.

Foydali dekorator misollari #

Python
from functools import wraps


def qayta_urin(marta=3):
    """Xato bo'lsa funksiyani belgilangan marta qayta chaqiradi."""
    def dekorator(funksiya):
        @wraps(funksiya)
        def orab_oluvchi(*args, **kwargs):
            for urinish in range(1, marta + 1):
                try:
                    return funksiya(*args, **kwargs)
                except Exception as xato:
                    print(f"  {urinish}-urinish muvaffaqiyatsiz: {xato}")
                    if urinish == marta:
                        raise
        return orab_oluvchi
    return dekorator


def kirish_talab_qilinadi(funksiya):
    """Foydalanuvchi tizimga kirganini tekshiradi."""
    @wraps(funksiya)
    def orab_oluvchi(foydalanuvchi, *args, **kwargs):
        if not foydalanuvchi.get("kirgan"):
            return "Ruxsat yo'q: avval tizimga kiring"
        return funksiya(foydalanuvchi, *args, **kwargs)
    return orab_oluvchi


@kirish_talab_qilinadi
def maxfiy_malumot(foydalanuvchi):
    return f"Salom {foydalanuvchi['ism']}, maxfiy ma'lumot: 42"


mehmon = {"ism": "Noma'lum", "kirgan": False}
egasi = {"ism": "Husanboy", "kirgan": True}

print(maxfiy_malumot(mehmon))
print(maxfiy_malumot(egasi))
Natija
Ruxsat yo'q: avval tizimga kiring
Salom Husanboy, maxfiy ma'lumot: 42

Tayyor dekoratorlar #

Python
from functools import lru_cache


@lru_cache(maxsize=None)
def fibonachchi(son):
    """Keshlash bilan - juda tez."""
    if son < 2:
        return son
    return fibonachchi(son - 1) + fibonachchi(son - 2)


print(fibonachchi(50))
print(fibonachchi.cache_info())
Natija
12586269025
CacheInfo(hits=48, misses=51, maxsize=None, currsize=51)
Keshsiz bu hisob-kitob soatlab davom etardi

fibonachchi(50) keshsiz taxminan 40 milliard marta chaqirilardi. @lru_cache bir marta hisoblangan natijani eslab qoladi va 51 ta chaqiruv bilan tugaydi.

DekoratorVazifasi
@propertyMetodni atribut kabi ishlatish
@staticmethodKlass ichidagi mustaqil funksiya
@classmethodKlassning o'zi bilan ishlaydigan metod
@lru_cacheNatijalarni keshlash
@wrapsDekoratorda meta-ma'lumotni saqlash
@abstractmethodMajburiy amalga oshiriladigan metod

@staticmethod va @classmethod #

Python
class Sana:
    def __init__(self, kun, oy, yil):
        self.kun, self.oy, self.yil = kun, oy, yil

    @classmethod
    def matndan(cls, matn):
        """Alternativ konstruktor: "08.09.2026" -> Sana obyekti."""
        kun, oy, yil = map(int, matn.split("."))
        return cls(kun, oy, yil)

    @staticmethod
    def kabisa_yilmi(yil):
        """Klass yoki obyektga bog'liq bo'lmagan yordamchi funksiya."""
        return yil % 4 == 0 and (yil % 100 != 0 or yil % 400 == 0)

    def __str__(self):
        return f"{self.kun:02d}.{self.oy:02d}.{self.yil}"


sana = Sana.matndan("08.09.2026")
print(sana)
print(Sana.kabisa_yilmi(2026))
print(Sana.kabisa_yilmi(2028))
Natija
08.09.2026
False
True

Kontekst menejerlar #

with bilan ishlaydigan o'z obyektingizni yaratish:

Python
import time


class Taymer:
    """Kod blokining bajarilish vaqtini o'lchaydi."""

    def __init__(self, nomi):
        self.nomi = nomi

    def __enter__(self):
        self.boshlanish = time.perf_counter()
        print(f"[{self.nomi}] boshlandi...")
        return self

    def __exit__(self, xato_turi, xato_qiymati, izlar):
        davomiylik = time.perf_counter() - self.boshlanish
        if xato_turi is None:
            print(f"[{self.nomi}] tugadi: {davomiylik:.4f} soniya")
        else:
            print(f"[{self.nomi}] xato bilan tugadi: {xato_qiymati}")
        return False        # xatoni yashirmaymiz


with Taymer("Katta hisob-kitob"):
    jami = sum(son ** 2 for son in range(3_000_000))

print(f"Natija: {jami:,}")
Natija
[Katta hisob-kitob] boshlandi...
[Katta hisob-kitob] tugadi: 0.3517 soniya
Natija: 8,999,995,500,000,500,000

Yanada qisqa usul - contextlib:

Python
from contextlib import contextmanager
import time


@contextmanager
def taymer(nomi):
    boshlanish = time.perf_counter()
    try:
        yield
    finally:
        print(f"[{nomi}] {time.perf_counter() - boshlanish:.4f} soniya")


with taymer("Saralash"):
    katta_royxat = sorted(range(1_000_000), reverse=True)
Natija
[Saralash] 0.0821 soniya

itertools - kuchli vositalar #

Python
from itertools import count, cycle, chain, combinations, groupby

# Cheksiz sanoq
for son in count(10, 5):
    if son > 30:
        break
    print(son, end=" ")
print()

# Bir nechta ro'yxatni ketma-ket aylanish
for element in chain([1, 2], ["a", "b"], (True, False)):
    print(element, end=" ")
print()

# Kombinatsiyalar
jamoa = ["Husanboy", "Sardor", "Malika"]
for juftlik in combinations(jamoa, 2):
    print(" - ".join(juftlik))
Natija
10 15 20 25 30 
1 2 a b True False 
Husanboy - Sardor
Husanboy - Malika
Sardor - Malika
Amaliy topshiriq
  1. tub_sonlar(chegara) generator funksiyasini yozing - yield bilan tub sonlarni birma-bir qaytarsin.
  2. @vaqtni_olcha dekoratorini yozib, uni tub sonlarni hisoblashda sinab ko'ring.
  3. @lru_cache bilan rekursiv funksiya yozing va keshsiz variant bilan tezligini solishtiring.
  4. FaylYozuvchi kontekst menejerini yarating - with blokidan chiqishda faylga "Yakunlandi" deb yozsin.

Xulosa #

  • Comprehension'lar ro'yxat, to'plam va lug'at uchun ishlaydi.
  • Generator elementlarni talab bo'yicha hosil qiladi va xotirani tejaydi; yield bilan yoziladi.
  • Dekorator funksiyani o'zgartirmasdan unga qo'shimcha xatti-harakat qo'shadi.
  • @lru_cache takroriy hisob-kitoblarni keskin tezlashtiradi.
  • __enter__ / __exit__ yoki @contextmanager bilan o'z with blokingizni yarating.
  • itertools moduli ketma-ketliklar bilan ishlashning tayyor vositalarini beradi.

Keyingi bo'limda standart kutubxonaning eng foydali modullarini batafsil ko'rib chiqamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.