IlmHamroh
Python kursi/Standart kutubxona10/16-dars27 daqiqa
Mundarija (21)

15.10-dars: functools to'liq

15-QISM — STANDART KUTUBXONA · 10-dars


1. Kirish va motivatsiya

functools bilan kurs davomida ko'p marta uchrashdik: wraps 10.11-bob, cache, partial, reduce 10.13-bob, singledispatch 8.9-bob, total_ordering 8.12-bob, cached_property 8.15-bob. Har biri o'z mavzusi ichida o'rganildi.

Bu dars — yakuniy xarita. Uch maqsad:

  1. Modulning barcha vositalarini bitta jadvalda ko'rish: nima uchun, qachon va qayerda o'rganilgan.
  2. Hali ko'rilmagan nozik joylar: kesh va konkurentlik (asyncio, iplar), singledispatch ning noaniq tanlovi, total_ordering narxi, cmp_to_key.
  3. Vositalarni birgalikda ishlatish — real xizmatda.

Real vaziyat. Valyuta kurslari xizmatida tashqi API chaqiruvi @functools.cache bilan keshlandi:

python
@cache
async def kurs_ol(valyuta: str) -> float:
    ...

Lokal testda bitta so'rov — hammasi ishladi. Ishlab chiqarishda ikkinchi so'rov RuntimeError: cannot reuse already awaited coroutine bilan yiqildi. Sabab: cache natijani emas, korutina obyektini saqlagan edi — uni esa faqat bir marta await qilish mumkin.

Xuddi shu xizmatda iplar bilan ishlaydigan qismda lru_cache "bir marta hisoblash"ni kafolatlaydi deb o'ylashdi. Kesh bo'shligida 8 ta so'rov bir vaqtda kelganda tashqi API 8 marta chaqirildi va limitdan oshib, bloklandi.

Bu darsda shunday nozik joylarni o'lchaymiz va hammasini birlashtirgan xizmat quramiz.

Bu darsda:

  • functools xaritasi: 13 ta vosita bir jadvalda
  • Kesh va konkurentlik: async funksiya, iplar, cached_property (3.12 o'zgarishi)
  • Kesh kaliti va turlar: 1, 1.0, True, typed=True
  • singledispatch chuqur: MRO, ABC, noaniq tanlov, birlashma turlar, singledispatchmethod
  • total_ordering narxi va NotImplemented
  • cmp_to_key — taqqoslash funksiyasidan kalitga; o'zbek alifbosi bo'yicha saralash
  • reduce va o'rnatilgan funksiyalar
  • Amaliy: valyuta xizmati — vositalarni birgalikda ishlatish

2. Nazariya — chuqur tushuntirish

2.1. functools xaritasi

Vosita Nima qiladi Qayerda o'rganildi
wraps, update_wrapper O'ramga asl funksiya metama'lumotini ko'chiradi 10.11
cache Chegarasiz kesh 10.13
lru_cache(maxsize, typed) LRU kesh, statistika 10.13, 15.7
cached_property Bir marta hisoblanadigan atribut 8.15, 10.17
partial Argumentlarni oldindan bog'lash 10.13
partialmethod Metodlar uchun partial 10.13
Placeholder (3.14) partial da pozitsion argumentni o'tkazib yuborish 10.13
reduce Chap yig'ish 7.12, 10.13
singledispatch Birinchi argument turi bo'yicha yuborish 8.9
singledispatchmethod Metodlar uchun 8.9, 8.16
total_ordering Bitta taqqoslashdan qolganlarini yasash 8.12
cmp_to_key Eski uslubdagi taqqoslash funksiyasini key ga 6.3, bu dars
WRAPPER_ASSIGNMENTS, WRAPPER_UPDATES wraps nimani ko'chirishini belgilovchi konstantalar 10.11

2.2. Kesh va konkurentlik

Holat Nima bo'ladi Yechim
@cache + async def Korutina obyekti keshlanadi → ikkinchi await da RuntimeError Natijani keshlash: lug'at + asyncio.Lock, yoki async kesh kutubxonasi
lru_cache + iplar, bo'sh kesh Ichki tuzilma ip-xavfsiz, lekin funksiya bir necha marta bajarilishi mumkin ("cache stampede") Kalit bo'yicha qulf
cached_property + iplar 3.12 dan beri qulf yo'q — bir necha marta hisoblanishi mumkin Kerak bo'lsa o'z qulfingiz
cached_property + __slots__ TypeError: __dict__ yo'q __slots__ ga "__dict__" qo'shish yoki lru_cache li metod

lru_cache natijaning to'g'riligini kafolatlaydi (oxir-oqibat bitta qiymat saqlanadi), lekin chaqiruvlar sonini kafolatlamaydi.

2.3. Kesh kaliti va turlar

Kesh kaliti argumentlardan yasaladi 10.13-bob. Bir argumentli chaqiruvda int va str uchun tezkor yo'l bor — kalit argumentning o'zi; boshqa turlar kortejga o'raladi. Natijada:

python
@cache
def tur(x): return type(x).__name__

tur(1)      # 'int'
tur(1.0)    # 'float' — 1 bilan teng bo'lsa ham alohida kalit
tur(True)   # 'float' — ⚠️ (True,) == (1.0,) → 1.0 ning natijasi
Sozlama Xulq
typed=False (sukut) Teng qiymatlar bir kalitga tushishi mumkin — tartib va tezkor yo'lga bog'liq
typed=True Tur ham kalitga kiradi — 1, 1.0, True alohida

Funksiya natijasi argument turiga bog'liq bo'lsa — lru_cache(typed=True).

2.4. singledispatch chuqur

Yuborish (dispatch) birinchi argumentning sinfi MRO si bo'yicha eng mos ro'yxatdan o'tgan turni topadi. ABC lar (Sized, Iterable) ham hisobga olinadi.

Holat Natija
Aniq tur ro'yxatda Shu realizatsiya
Ota sinf ro'yxatda MRO bo'yicha eng yaqini
Ikki ABC teng darajada mos RuntimeError: Ambiguous dispatch
bool qiymat, int ro'yxatda int realizatsiyasi — bool — int vorisi
int | float annotatsiya (3.11+) Har ikkala tur ro'yxatga olinadi
Hech biri mos emas Asosiy (object) funksiya

Noaniqlik ko'rinmas joyda chiqadi: Sized va Iterable ro'yxatdan o'tkazilsa, oddiy list ham ikkalasiga teng mos keladi va RuntimeError beradi. Yechim: umumiyroq (Collection) yoki aniq tur (list) uchun alohida realizatsiya. Collection faqat __len__, __iter__ va __contains__ ga ega sinflarni qamraydi — faqat __len__ va __iter__ li o'z sinfingiz uchun baribir aniq realizatsiya kerak (Misol 2).

API Vazifasi
f.register(tur) / annotatsiya bilan Realizatsiya qo'shish
f.dispatch(tur) Qaysi realizatsiya tanlanishini ko'rish
f.registry Barcha ro'yxatdagilar
singledispatchmethod Metodlar — yuborish ikkinchi argument (self dan keyingi) bo'yicha

singledispatchmethod bilan classmethod/staticmethod birga ishlatilganda @singledispatchmethod tashqarida bo'lishi kerak.

2.5. total_ordering narxi

@total_ordering bitta taqqoslash (__lt__) va __eq__ dan qolgan to'rttasini yasaydi.

Xususiyat Tafsilot
Qulaylik Kam kod, xatolar kamroq
Narxi Yasalgan metodlar qo'shimcha chaqiruv qiladi — sekinroq
NotImplemented To'g'ri qaytarilsa, yasalgan metodlar ham uni to'g'ri uzatadi
Qachon qo'lda yozish Juda ko'p taqqoslanadigan "issiq" kod (saralash, heap)

Zamonaviy muqobil: @dataclass(order=True) — maydonlar kortej sifatida taqqoslanadi 8.17-bob.

2.6. cmp_to_key

Python 2 da sorted(xs, cmp=f) — f(a, b) manfiy, nol yoki musbat qaytarardi. Python 3 da faqat key bor. cmp_to_key eski taqqoslash funksiyasini kalit obyektiga o'raydi.

Qachon cmp_to_key Qachon oddiy key
Tashqi kutubxonadan taqqoslash funksiyasi Deyarli har doim
Juftlik taqqoslash kalitga keltirilmaydi (masalan, a+b va b+a satrlarini solishtirish) Kalitni hisoblash mumkin
key tezroq: har element uchun bir marta hisoblanadi

2.7. reduce va o'rnatilgan funksiyalar

Vazifa reduce bilan Yaxshirog'i
Yig'indi reduce(add, xs) sum(xs)
Ko'paytma reduce(mul, xs) math.prod(xs)
Maksimum reduce(max, xs) max(xs)
Hammasi rostmi reduce(and_, xs) all(xs)
Lug'atlarni birlashtirish reduce(or_, dicts, {}) reduce o'rinli
Funksiyalar kompozitsiyasi reduce(lambda f, g: ..., fs) O'rinli

Bo'sh ketma-ketlik va boshlang'ich qiymatsiz — TypeError: reduce() of empty iterable with no initial value.


3. Tez ma'lumotnoma

python
import functools as ft

@ft.lru_cache(maxsize=1024, typed=True)          # tur muhim bo'lsa typed
def hisobla(x): ...

@ft.singledispatch
def formatla(x): return str(x)
@formatla.register
def _(x: int | float): ...
formatla.dispatch(bool)                          # qaysi realizatsiya?

@ft.total_ordering
class Versiya: ...                               # __eq__ + __lt__

sorted(sozlar, key=ft.cmp_to_key(taqqosla))      # eski taqqoslash funksiyasi
ft.reduce(lambda f, g: lambda x: g(f(x)), bosqichlar)   # kompozitsiya

Qoidalar

async funksiyaga @cache qo'ymang
lru_cache chaqiruvlar sonini kafolatlamaydi — stampede
cached_property 3.12+ da qulfsiz
tur muhim — typed=True
singledispatch: teng mos ABC lar — RuntimeError
total_ordering — qulay, lekin sekinroq
key — cmp_to_key dan afzal

4. Batafsil misollar

Misol 1 — Kesh va konkurentlik

python
"""@cache va async funksiya; to'g'ri async kesh; lru_cache va iplar — stampede; kalit bo'yicha qulf; cached_property qulfsizligi; __slots__ bilan cached_property; typed=True."""

import asyncio
import functools as ft
import threading
import time


@ft.cache
async def xato_kurs(valyuta: str) -> float:
    await asyncio.sleep(0)
    return {"USD": 12_650.0, "EUR": 13_900.0}[valyuta]


class AsyncKesh:
    def __init__(self) -> None:
        self.natijalar: dict[str, float] = {}
        self.qulflar: dict[str, asyncio.Lock] = {}
        self.chaqiruvlar = 0

    async def kurs(self, valyuta: str) -> float:
        if valyuta in self.natijalar:
            return self.natijalar[valyuta]
        qulf = self.qulflar.setdefault(valyuta, asyncio.Lock())
        async with qulf:
            if valyuta not in self.natijalar:          # qulfdan keyin qayta tekshiruv
                self.chaqiruvlar += 1
                await asyncio.sleep(0.01)
                self.natijalar[valyuta] = {"USD": 12_650.0, "EUR": 13_900.0}[valyuta]
        return self.natijalar[valyuta]


async def async_qism() -> None:
    birinchi = await xato_kurs("USD")
    try:
        await xato_kurs("USD")
    except RuntimeError as xato:
        print(f"  @cache + async: birinchi={birinchi}, ikkinchi → RuntimeError: {xato}")
    kesh = AsyncKesh()
    natijalar = await asyncio.gather(*(kesh.kurs("USD") for _ in range(10)))
    print(f"  to'g'ri async kesh: 10 so'rov, natijalar bir xil: {len(set(natijalar)) == 1}, API chaqiruvlari: {kesh.chaqiruvlar}")


def main() -> None:
    print("=== 1. ⚠️ Asinxron funksiyani keshlash ===")
    asyncio.run(async_qism())

    print("\n=== 2. ⚠️ lru_cache va iplar: stampede ===")
    chaqiruvlar = 0
    hisob_qulfi = threading.Lock()

    @ft.lru_cache(maxsize=None)
    def sekin_kurs(valyuta: str) -> float:
        nonlocal chaqiruvlar
        with hisob_qulfi:
            chaqiruvlar += 1
        time.sleep(0.1)
        return 12_650.0

    iplar = [threading.Thread(target=sekin_kurs, args=("USD",)) for _ in range(8)]
    for ip in iplar:
        ip.start()
    for ip in iplar:
        ip.join()
    print(f"  8 ip bir vaqtda: funksiya bir martadan ko'p bajarildi: {chaqiruvlar > 1}")
    print(f"  keshda baribir bitta yozuv: {sekin_kurs.cache_info().currsize == 1}")

    print("\n=== 3. Kalit bo'yicha qulf ===")
    natijalar: dict[str, float] = {}
    qulflar: dict[str, threading.Lock] = {}
    qulflar_qulfi = threading.Lock()
    haqiqiy = 0

    def himoyalangan_kurs(valyuta: str) -> float:
        nonlocal haqiqiy
        if valyuta in natijalar:
            return natijalar[valyuta]
        with qulflar_qulfi:
            qulf = qulflar.setdefault(valyuta, threading.Lock())
        with qulf:
            if valyuta not in natijalar:
                haqiqiy += 1
                time.sleep(0.1)
                natijalar[valyuta] = 12_650.0
        return natijalar[valyuta]

    iplar = [threading.Thread(target=himoyalangan_kurs, args=("USD",)) for _ in range(8)]
    for ip in iplar:
        ip.start()
    for ip in iplar:
        ip.join()
    print(f"  8 ip: haqiqiy chaqiruvlar = {haqiqiy}")

    print("\n=== 4. ⚠️ cached_property: 3.12+ da qulfsiz ===")
    hisoblandi = 0

    class Hisobot:
        @ft.cached_property
        def jami(self) -> int:
            nonlocal hisoblandi
            hisoblandi += 1
            time.sleep(0.05)
            return 42

    h = Hisobot()
    iplar = [threading.Thread(target=lambda: h.jami) for _ in range(5)]
    for ip in iplar:
        ip.start()
    for ip in iplar:
        ip.join()
    print(f"  5 ip: hisoblash bir martadan ko'p: {hisoblandi > 1}, qiymat: {h.jami}")

    class Slotli:
        __slots__ = ("x",)

        @ft.cached_property
        def ogir(self) -> int:
            return 1

    try:
        Slotli().ogir
    except TypeError as xato:
        print(f"  __slots__ bilan: TypeError: {xato}")

    print("\n=== 5. ⚠️ Kesh kaliti va turlar ===")

    @ft.cache
    def tur(x: object) -> str:
        return type(x).__name__

    @ft.lru_cache(typed=True)
    def tur_typed(x: object) -> str:
        return type(x).__name__

    print(f"  cache:       1→{tur(1)}, 1.0→{tur(1.0)}, True→{tur(True)}")
    print(f"  typed=True:  1→{tur_typed(1)}, 1.0→{tur_typed(1.0)}, True→{tur_typed(True)}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. ⚠️ Asinxron funksiyani keshlash ===
  @cache + async: birinchi=12650.0, ikkinchi → RuntimeError: cannot reuse already awaited coroutine
  to'g'ri async kesh: 10 so'rov, natijalar bir xil: True, API chaqiruvlari: 1

=== 2. ⚠️ lru_cache va iplar: stampede ===
  8 ip bir vaqtda: funksiya bir martadan ko'p bajarildi: True
  keshda baribir bitta yozuv: True

=== 3. Kalit bo'yicha qulf ===
  8 ip: haqiqiy chaqiruvlar = 1

=== 4. ⚠️ cached_property: 3.12+ da qulfsiz ===
  5 ip: hisoblash bir martadan ko'p: True, qiymat: 42
  __slots__ bilan: TypeError: No '__dict__' attribute on 'Slotli' instance to cache 'ogir' property.

=== 5. ⚠️ Kesh kaliti va turlar ===
  cache:       1→int, 1.0→float, True→float
  typed=True:  1→int, 1.0→float, True→bool

Nima ko'rsatdi: 2.2, 2.3-bo'limlar.

Misol 2 — singledispatch chuqur

python
"""MRO bo'yicha tanlov; ABC lar va noaniq tanlov (list ham!); tuzatish; birlashma turlar; bool va int; dispatch va registry; singledispatchmethod va classmethod."""

import functools as ft
from collections.abc import Collection, Iterable, Mapping, Sized
from datetime import date
from decimal import Decimal


@ft.singledispatch
def tavsif(x: object) -> str:
    return "noma'lum"


@tavsif.register
def _(x: Sized) -> str:
    return f"o'lchamli ({len(x)})"


@tavsif.register
def _(x: Iterable) -> str:
    return "aylanadigan"


class Toplam:
    def __len__(self) -> int:
        return 3

    def __iter__(self):
        return iter([1, 2, 3])


class Sanoq:
    def __len__(self) -> int:
        return 7


@ft.singledispatch
def formatla(x: object) -> str:
    return str(x)


@formatla.register
def _(x: int | float) -> str:
    return f"{x:,}".replace(",", " ")


@formatla.register
def _(x: bool) -> str:
    return "ha" if x else "yo'q"


@formatla.register
def _(x: Decimal) -> str:
    return f"{x:.2f} so'm"


@formatla.register
def _(x: date) -> str:
    return f"{x:%d.%m.%Y}"


@formatla.register
def _(x: Mapping) -> str:
    return ", ".join(f"{k}={formatla(v)}" for k, v in x.items())


class Eksport:
    @ft.singledispatchmethod
    @classmethod
    def qiymat(cls, x: object) -> str:
        return f"<{type(x).__name__}>"

    @qiymat.register
    @classmethod
    def _(cls, x: int) -> str:
        return f"butun:{x}"

    @qiymat.register
    @classmethod
    def _(cls, x: str) -> str:
        return f"satr:{x!r}"


def main() -> None:
    print("=== 1. ⚠️ Noaniq tanlov ===")
    print(f"  Sanoq (faqat __len__): {tavsif(Sanoq())}")
    for nom, qiymat in (("Toplam", Toplam()), ("list", [1, 2])):
        try:
            tavsif(qiymat)
        except RuntimeError as xato:
            print(f"  {nom}: RuntimeError: {str(xato)[:60]}...")
    print(f"  aniq qiymat: {tavsif.dispatch(Sanoq).__name__} — '_' deb nomlangan realizatsiya")

    @tavsif.register
    def _(x: Collection) -> str:
        return f"to'plam ({len(x)})"

    print(f"  Collection qo'shilgach: list → {tavsif([1, 2])}")
    try:
        tavsif(Toplam())
    except RuntimeError:
        print(f"  ⚠️ Toplam hali ham noaniq: __contains__ yo'q → Collection emas: {not issubclass(Toplam, Collection)}")
    tavsif.register(Toplam, lambda x: "Toplam (aniq realizatsiya)")
    print(f"  aniq tur ro'yxatga olingach: {tavsif(Toplam())}")

    print("\n=== 2. Birlashma turlar va bool ===")
    for x in (1234567, 3.5, True, Decimal("12650.5"), date(2026, 9, 17), "matn", {"narx": 45000, "faol": False}):
        print(f"  {type(x).__name__:8} → {formatla(x)}")
    print(f"  ro'yxatdagi turlar: {sorted(t.__name__ for t in formatla.registry)}")
    print(f"  bool uchun alohida realizatsiya bo'lmasa int ishlardi: {issubclass(bool, int)}")

    print("\n=== 3. dispatch() — tanlovni tekshirish ===")
    for tur in (int, bool, float, dict, list):
        realizatsiya = formatla.dispatch(tur)
        print(f"  {tur.__name__:5} → asosiy funksiyami: {realizatsiya is formatla.registry[object]}")

    print("\n=== 4. singledispatchmethod + classmethod ===")
    for x in (42, "Wisar", 3.14):
        print(f"  Eksport.qiymat({x!r}) → {Eksport.qiymat(x)}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. ⚠️ Noaniq tanlov ===
  Sanoq (faqat __len__): o'lchamli (7)
  Toplam: RuntimeError: Ambiguous dispatch: <class 'collections.abc.Sized'> or <clas...
  list: RuntimeError: Ambiguous dispatch: <class 'collections.abc.Sized'> or <clas...
  aniq qiymat: _ — '_' deb nomlangan realizatsiya
  Collection qo'shilgach: list → to'plam (2)
  ⚠️ Toplam hali ham noaniq: __contains__ yo'q → Collection emas: True
  aniq tur ro'yxatga olingach: Toplam (aniq realizatsiya)

=== 2. Birlashma turlar va bool ===
  int      → 1 234 567
  float    → 3.5
  bool     → ha
  Decimal  → 12650.50 so'm
  date     → 17.09.2026
  str      → matn
  dict     → narx=45 000, faol=yo'q
  ro'yxatdagi turlar: ['Decimal', 'Mapping', 'bool', 'date', 'float', 'int', 'object']
  bool uchun alohida realizatsiya bo'lmasa int ishlardi: True

=== 3. dispatch() — tanlovni tekshirish ===
  int   → asosiy funksiyami: False
  bool  → asosiy funksiyami: False
  float → asosiy funksiyami: False
  dict  → asosiy funksiyami: False
  list  → asosiy funksiyami: True

=== 4. singledispatchmethod + classmethod ===
  Eksport.qiymat(42) → butun:42
  Eksport.qiymat('Wisar') → satr:'Wisar'
  Eksport.qiymat(3.14) → <float>

Nima ko'rsatdi: 2.4-bo'lim.

Misol 3 — total_ordering, cmp_to_key, reduce

python
"""total_ordering: to'g'rilik va narx; dataclass(order=True) muqobili; cmp_to_key: eski taqqoslash va eng katta son masalasi; o'zbek alifbosi bo'yicha saralash; reduce: lug'atlar va funksiyalar kompozitsiyasi."""

import functools as ft
import operator
import timeit
from dataclasses import dataclass


@ft.total_ordering
class VersiyaTO:
    def __init__(self, satr: str) -> None:
        self.qismlar = tuple(int(q) for q in satr.split("."))

    def __eq__(self, boshqa: object) -> bool:
        if not isinstance(boshqa, VersiyaTO):
            return NotImplemented
        return self.qismlar == boshqa.qismlar

    def __lt__(self, boshqa: object) -> bool:
        if not isinstance(boshqa, VersiyaTO):
            return NotImplemented
        return self.qismlar < boshqa.qismlar


class VersiyaQolda(VersiyaTO):
    def __ge__(self, boshqa: object) -> bool:
        if not isinstance(boshqa, VersiyaTO):
            return NotImplemented
        return self.qismlar >= boshqa.qismlar


@dataclass(frozen=True, order=True)
class VersiyaDC:
    katta: int
    kichik: int
    tuzatish: int


ALIFBO = ["a", "b", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
          "u", "v", "x", "y", "z", "oʻ", "gʻ", "sh", "ch", "ng"]
TARTIB = {harf: i for i, harf in enumerate(ALIFBO)}


def harflarga(soz: str) -> list[str]:
    soz = soz.lower().replace("'", "ʻ").replace("‘", "ʻ")
    harflar, i = [], 0
    while i < len(soz):
        ikki = soz[i:i + 2]
        if ikki in TARTIB:
            harflar.append(ikki)
            i += 2
        else:
            harflar.append(soz[i])
            i += 1
    return harflar


def ozbek_kaliti(soz: str) -> list[int]:
    return [TARTIB.get(h, len(ALIFBO)) for h in harflarga(soz)]


def main() -> None:
    print("=== 1. total_ordering ===")
    a, b = VersiyaTO("3.12.1"), VersiyaTO("3.9.8")
    print(f"  3.12.1 > 3.9.8: {a > b}, <=: {a <= b}, >=: {a >= b}  (satr sifatida: {'3.12.1' > '3.9.8'})")
    print(f"  boshqa tur bilan ==: {a == '3.12.1'}")
    try:
        a < "3.12.1"
    except TypeError:
        print("  boshqa tur bilan < → TypeError (NotImplemented to'g'ri uzatildi)")
    yasalgan = min(timeit.repeat(lambda: a >= b, number=200_000, repeat=5))
    qolda = VersiyaQolda("3.12.1"), VersiyaQolda("3.9.8")
    qolda_vaqt = min(timeit.repeat(lambda: qolda[0] >= qolda[1], number=200_000, repeat=5))
    print(f"  yasalgan __ge__ qo'lda yozilgandan sekinroq: {yasalgan > qolda_vaqt}")
    print(f"  dataclass(order=True): {VersiyaDC(3, 12, 1) > VersiyaDC(3, 9, 8)}")

    print("\n=== 2. cmp_to_key: kalitga keltirib bo'lmaydigan taqqoslash ===")
    sonlar = [3, 30, 34, 5, 9]

    def juftlik_taqqos(x: str, y: str) -> int:
        return (x + y < y + x) - (x + y > y + x)      # xy katta bo'lsa x oldinda

    eng_katta = "".join(sorted(map(str, sonlar), key=ft.cmp_to_key(juftlik_taqqos)))
    oddiy = "".join(sorted(map(str, sonlar), reverse=True))
    print(f"  {sonlar} dan eng katta son: {eng_katta}")
    print(f"  oddiy teskari saralash:      {oddiy}  ← noto'g'ri")

    print("\n=== 3. O'zbek alifbosi bo'yicha saralash ===")
    sozlar = ["choy", "olma", "shaftoli", "o'rik", "gilos", "g'isht", "anor", "nok", "zira", "sabzi"]
    print(f"  sorted() (Unicode kodlari): {sorted(sozlar)}")
    print(f"  o'zbek alifbosi:            {sorted(sozlar, key=ozbek_kaliti)}")

    def eski_taqqos(x: str, y: str) -> int:
        kx, ky = ozbek_kaliti(x), ozbek_kaliti(y)
        return (kx > ky) - (kx < ky)

    print(f"  cmp_to_key bilan bir xil: {sorted(sozlar, key=ft.cmp_to_key(eski_taqqos)) == sorted(sozlar, key=ozbek_kaliti)}")

    print("\n=== 4. reduce ===")
    sozlamalar = [{"host": "localhost", "port": 5432}, {"port": 6543}, {"debug": True}]
    print(f"  lug'atlarni birlashtirish: {ft.reduce(operator.or_, sozlamalar, {})}")
    bosqichlar = [str.strip, str.lower, lambda s: " ".join(s.split())]
    tozala = ft.reduce(lambda f, g: lambda x: g(f(x)), bosqichlar)
    print(f"  funksiyalar kompozitsiyasi: {tozala('   SALOM    DUNYO  ')!r}")
    try:
        ft.reduce(operator.add, [])
    except TypeError as xato:
        print(f"  bo'sh ro'yxat: TypeError: {xato}")
    print(f"  boshlang'ich qiymat bilan: {ft.reduce(operator.add, [], 0)}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. total_ordering ===
  3.12.1 > 3.9.8: True, <=: False, >=: True  (satr sifatida: False)
  boshqa tur bilan ==: False
  boshqa tur bilan < → TypeError (NotImplemented to'g'ri uzatildi)
  yasalgan __ge__ qo'lda yozilgandan sekinroq: True
  dataclass(order=True): True

=== 2. cmp_to_key: kalitga keltirib bo'lmaydigan taqqoslash ===
  [3, 30, 34, 5, 9] dan eng katta son: 9534330
  oddiy teskari saralash:      9534303  ← noto'g'ri

=== 3. O'zbek alifbosi bo'yicha saralash ===
  sorted() (Unicode kodlari): ['anor', 'choy', "g'isht", 'gilos', 'nok', "o'rik", 'olma', 'sabzi', 'shaftoli', 'zira']
  o'zbek alifbosi:            ['anor', 'gilos', 'nok', 'olma', 'sabzi', 'zira', "o'rik", "g'isht", 'shaftoli', 'choy']
  cmp_to_key bilan bir xil: True

=== 4. reduce ===
  lug'atlarni birlashtirish: {'host': 'localhost', 'port': 6543, 'debug': True}
  funksiyalar kompozitsiyasi: 'salom dunyo'
  bo'sh ro'yxat: TypeError: reduce() of empty iterable with no initial value
  boshlang'ich qiymat bilan: 0

Nima ko'rsatdi: 2.5, 2.6, 2.7-bo'limlar.

Misol 4 — Amaliy: valyuta xizmati

Kirishdagi xizmatni to'g'ri quramiz va functools vositalarini birgalikda ishlatamiz: total_ordering li Pul turi, lru_cache(typed=True) va muddatli kesh bilan kurs olish, partial bilan tayyor konvertorlar, singledispatch bilan formatlash, wraps bilan statistika dekoratori, cached_property bilan hisobot va reduce bilan narx quvuri. Vaqt hozir parametri bilan beriladi — natija takrorlanadi.

python
"""Pul (total_ordering) + kurs kesh (lru_cache, TTL) + partial konvertorlar + singledispatch formatlash + wraps dekorator + cached_property hisobot + reduce quvur."""

import functools as ft
from dataclasses import dataclass
from decimal import ROUND_HALF_UP, Decimal

API_KURSLARI = {"USD": Decimal("12650.00"), "EUR": Decimal("13900.00"), "RUB": Decimal("152.50")}
API_CHAQIRUVLARI: list[str] = []


def statistika(funksiya):
    @ft.wraps(funksiya)
    def oram(*args, **kwargs):
        oram.chaqiruvlar += 1
        return funksiya(*args, **kwargs)

    oram.chaqiruvlar = 0
    return oram


@ft.total_ordering
@dataclass(frozen=True, eq=False)
class Pul:
    miqdor: Decimal
    valyuta: str = "UZS"

    def __eq__(self, boshqa: object) -> bool:
        if not isinstance(boshqa, Pul):
            return NotImplemented
        return somga(self).miqdor == somga(boshqa).miqdor

    def __lt__(self, boshqa: object) -> bool:
        if not isinstance(boshqa, Pul):
            return NotImplemented
        return somga(self).miqdor < somga(boshqa).miqdor

    def __hash__(self) -> int:
        return hash(somga(self).miqdor)


@ft.lru_cache(maxsize=128, typed=True)
def _kurs_oynasi(valyuta: str, oyna: int) -> Decimal:
    API_CHAQIRUVLARI.append(f"{valyuta}@{oyna}")
    return API_KURSLARI[valyuta]


def kurs(valyuta: str, hozir: float, ttl: int = 300) -> Decimal:
    if valyuta == "UZS":
        return Decimal(1)
    return _kurs_oynasi(valyuta, int(hozir // ttl))    # TTL: har 5 daqiqada yangi kalit


HOZIR = 1_789_635_600.0


def somga(pul: Pul, hozir: float = HOZIR) -> Pul:
    miqdor = (pul.miqdor * kurs(pul.valyuta, hozir)).quantize(Decimal("1"), ROUND_HALF_UP)
    return Pul(miqdor, "UZS")


@statistika
def konvert(pul: Pul, maqsad: str, hozir: float = HOZIR) -> Pul:
    som = somga(pul, hozir).miqdor
    return Pul((som / kurs(maqsad, hozir)).quantize(Decimal("0.01"), ROUND_HALF_UP), maqsad)


dollarga = ft.partial(konvert, maqsad="USD")
yevroga = ft.partial(konvert, maqsad="EUR")


@ft.singledispatch
def korsat(x: object) -> str:
    return str(x)


@korsat.register
def _(x: Pul) -> str:
    butun = f"{x.miqdor:,.2f}".replace(",", " ") if x.valyuta != "UZS" else f"{x.miqdor:,.0f}".replace(",", " ")
    return f"{butun} {x.valyuta}"


@korsat.register
def _(x: list) -> str:
    return "; ".join(korsat(e) for e in x)


class Hisobot:
    def __init__(self, tolovlar: list[Pul]) -> None:
        self.tolovlar = tolovlar
        self.hisoblashlar = 0

    @ft.cached_property
    def jami_som(self) -> Pul:
        self.hisoblashlar += 1
        return Pul(sum((somga(t).miqdor for t in self.tolovlar), Decimal(0)))


def main() -> None:
    print("=== 1. Pul va taqqoslash ===")
    narx_usd, narx_eur, narx_som = Pul(Decimal("100"), "USD"), Pul(Decimal("90"), "EUR"), Pul(Decimal("1260000"))
    print(f"  100 USD = {korsat(somga(narx_usd))}, 90 EUR = {korsat(somga(narx_eur))}")
    print(f"  eng arzoni: {korsat(min(narx_usd, narx_eur, narx_som))}")
    print(f"  saralangan: {korsat(sorted([narx_usd, narx_eur, narx_som]))}")
    print(f"  100 USD >= 1 265 000 so'm: {narx_usd >= Pul(Decimal('1265000'))}")

    print("\n=== 2. Kesh va TTL ===")
    API_CHAQIRUVLARI.clear()
    _kurs_oynasi.cache_clear()                          # 1-bo'lim taqqoslashlari keshni to'ldirgan edi
    for soniya in (0, 10, 299, 300, 305):
        kurs("USD", HOZIR + soniya)
    print(f"  5 so'rov, API chaqiruvlari: {len(API_CHAQIRUVLARI)} (oynalar: {API_CHAQIRUVLARI})")
    print(f"  {_kurs_oynasi.cache_info()}")

    print("\n=== 3. partial konvertorlar va wraps ===")
    print(f"  1 000 000 so'm → {korsat(dollarga(Pul(Decimal('1000000'))))}")
    print(f"  250 USD → {korsat(yevroga(Pul(Decimal('250'), 'USD')))}")
    print(f"  konvert.__name__ = {konvert.__name__}, chaqiruvlar = {konvert.chaqiruvlar}")
    print(f"  dollarga.func is konvert: {dollarga.func is konvert}, keywords: {dollarga.keywords}")

    print("\n=== 4. cached_property hisobot ===")
    hisobot = Hisobot([narx_usd, narx_eur, narx_som, Pul(Decimal("5000"), "RUB")])
    for _ in range(3):
        jami = hisobot.jami_som
    print(f"  jami: {korsat(jami)}, hisoblashlar: {hisobot.hisoblashlar}")
    del hisobot.jami_som
    print(f"  del dan keyin qayta: {korsat(hisobot.jami_som)}, hisoblashlar: {hisobot.hisoblashlar}")

    print("\n=== 5. reduce: narx quvuri ===")
    bosqichlar = [
        ("chegirma 10%", lambda p: Pul((p.miqdor * Decimal("0.90")).quantize(Decimal("1")), p.valyuta)),
        ("QQS 12%", lambda p: Pul((p.miqdor * Decimal("1.12")).quantize(Decimal("1")), p.valyuta)),
        ("yetkazish +25 000", lambda p: Pul(p.miqdor + 25_000, p.valyuta)),
    ]
    boshlangich = somga(narx_usd)
    yakuniy = ft.reduce(lambda pul, bosqich: bosqich[1](pul), bosqichlar, boshlangich)
    print(f"  {korsat(boshlangich)} → {' → '.join(nom for nom, _ in bosqichlar)} → {korsat(yakuniy)}")


if __name__ == "__main__":
    main()

Natijaning muhim qismi:

text
=== 1. Pul va taqqoslash ===
  100 USD = 1 265 000 UZS, 90 EUR = 1 251 000 UZS
  eng arzoni: 90.00 EUR
  saralangan: 90.00 EUR; 1 260 000 UZS; 100.00 USD
  100 USD >= 1 265 000 so'm: True

=== 2. Kesh va TTL ===
  5 so'rov, API chaqiruvlari: 2 (oynalar: ['USD@5965452', 'USD@5965453'])
  CacheInfo(hits=3, misses=2, maxsize=128, currsize=2)

=== 3. partial konvertorlar va wraps ===
  1 000 000 so'm → 79.05 USD
  250 USD → 227.52 EUR
  konvert.__name__ = konvert, chaqiruvlar = 2
  dollarga.func is konvert: True, keywords: {'maqsad': 'USD'}

=== 4. cached_property hisobot ===
  jami: 4 538 500 UZS, hisoblashlar: 1
  del dan keyin qayta: 4 538 500 UZS, hisoblashlar: 2

=== 5. reduce: narx quvuri ===
  1 265 000 UZS → chegirma 10% → QQS 12% → yetkazish +25 000 → 1 300 120 UZS

Nima ko'rsatdi: 2.1–2.7-bo'limlar.


5. To'g'ri va noto'g'ri tushunishlar

Noto'g'ri fikr To'g'risi
"@cache istalgan funksiyaga qo'yiladi" async def da korutina keshlanadi — RuntimeError
"lru_cache bilan funksiya bir marta bajariladi" Bir vaqtdagi chaqiruvlarda bir necha marta
"cached_property ip-xavfsiz" 3.12 dan beri qulfsiz
"cache da 1, 1.0, True doim bir kalit" Tezkor yo'lga bog'liq — typed=True bilan aniq
"singledispatch doim eng mosini topadi" Teng mos ABC larda RuntimeError
"bool uchun int realizatsiyasi ishlamaydi" Ishlaydi — bool int vorisi
"total_ordering bepul" Yasalgan metodlar sekinroq
"cmp_to_key — key bilan bir xil tezlik" key tezroq; cmp_to_key — kalit yasab bo'lmaganda

6. Keng tarqalgan xatolar va yechimlari

1. async funksiyaga @cache

python
@cache
async def ol(x): ...                          # ❌
# ✅ natijani lug'atda saqlash + asyncio.Lock (Misol 1)

2. Stampede

python
@lru_cache
def tashqi_api(k): ...                        # ⚠️ bo'sh keshda parallel chaqiruvlar
# ✅ kalit bo'yicha qulf yoki kesh oldindan to'ldirilishi

3. __slots__ va cached_property

python
class A:
    __slots__ = ("x",)
    @cached_property
    def y(self): ...                          # ❌ TypeError

4. Teng mos ABC lar

python
@f.register
def _(x: Sized): ...
@f.register
def _(x: Iterable): ...                       # ⚠️ list → RuntimeError
@f.register
def _(x: Collection): ...                     # ✅

5. singledispatchmethod bezaklari tartibi

python
@classmethod
@singledispatchmethod                         # ❌
@singledispatchmethod
@classmethod                                  # ✅

6. Qiymat turiga bog'liq keshlash

python
@cache
def formatla(x): return f"{type(x).__name__}:{x}"    # ❌ 1.0 va True aralashadi
@lru_cache(typed=True)                               # ✅

7. reduce bilan yig'indi

python
reduce(operator.add, sonlar)                  # ❌ bo'shda xato, sekin
sum(sonlar)                                   # ✅

8. Kalit yasash mumkin bo'lganda cmp_to_key

python
sorted(xs, key=cmp_to_key(lambda a, b: a.yosh - b.yosh))   # ❌
sorted(xs, key=lambda a: a.yosh)                           # ✅

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 8.9, 8.12, 8.15-darslar (o'tilgan): singledispatch, total_ordering, cached_property
  • 10.11, 10.13-darslar (o'tilgan): wraps, cache, partial, reduce
  • 14.3, 14.6-darslar (o'tilgan): iplar, asyncio.Lock
  • 15.7-dars (o'tilgan): LRU kesh OrderedDict bilan
  • 18.7-dars: profiling — keshlash foydasini o'lchash
  • 29.3-dars: kesh strategiyalari — stampede
  • 23.10-dars: Redis va kesh — taqsimlangan kesh

8. Eng yaxshi amaliyotlar

  1. Keshni qo'yishdan oldin so'rang: funksiya sofmi, argumentlari xeshlanadimi, konkurent chaqiriladimi, async mi?

  2. Tur muhim — typed=True.

  3. Tashqi resurs keshida — stampede himoyasi.

  4. singledispatch — umumiyroq ABC dan aniqrog'iga qarab ro'yxatdan o'tkazing va dispatch() bilan tekshiring.

  5. "Issiq" taqqoslashlarda total_ordering o'rniga qo'lda yoki dataclass(order=True).

  6. key — birinchi tanlov, cmp_to_key — faqat kalit yasab bo'lmaganda.

  7. reduce — kompozitsiya va birlashtirish uchun; yig'indi va ko'paytma uchun o'rnatilgan funksiyalar.

  8. Vaqtga bog'liq keshlarni hozir parametri bilan testlanadigan qiling.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
import functools as ft
1.  print(ft.reduce(lambda a, b: a * b, [1, 2, 3, 4]))
2.  print(ft.reduce(lambda a, b: a + b, [], 10))
3.  print(ft.partial(pow, 2)(5))
4.  print(ft.partial(int, base=16)("ff"))
5.  @ft.singledispatch
    def f(x): return "obj"
    @f.register
    def _(x: int): return "int"
    print(f(True), f(2.0))
6.  @ft.lru_cache(typed=True)
    def g(x): return type(x).__name__
    print(g(1), g(1.0))
7.  print(sorted([3, 1, 2], key=ft.cmp_to_key(lambda a, b: b - a)))
8.  @ft.total_ordering
    class A:
        def __init__(self, v): self.v = v
        def __eq__(self, o): return self.v == o.v
        def __lt__(self, o): return self.v < o.v
    print(A(2) >= A(1), A(1) > A(1))
9.  class B:
        @ft.cached_property
        def x(self): return [1]
    b = B(); print(b.x is b.x)
10. @ft.cache
    def h(n): return n
    h(1); h(1); print(h.cache_info().hits)
11. print(ft.reduce(lambda acc, s: acc | s, [{1}, {2}, {1, 3}], set()))
12. @ft.singledispatch
    def k(x): return "obj"
    @k.register
    def _(x: int | str): return "int|str"
    print(k("a"), k(3), k(3.0))
Javoblar
  1. 24
  2. 10
  3. 32
  4. 255
  5. int obj — bool int vorisi
  6. int float
  7. [3, 2, 1]
  8. True False
  9. True
  10. 1
  11. {1, 2, 3}
  12. int|str int|str obj

Vazifa 2: Xatolarni tuzating

python
1.  @functools.cache
    async def foydalanuvchi(id_):
        return await db.ol(id_)

2.  class Model:
        __slots__ = ("vaznlar",)
        @functools.cached_property
        def norma(self):
            return hisobla(self.vaznlar)

3.  @functools.singledispatch
    def serializatsiya(x): raise TypeError(x)
    @serializatsiya.register
    def _(x: Sized): ...
    @serializatsiya.register
    def _(x: Iterable): ...
    serializatsiya([1, 2])

4.  @functools.cache
    def kalit_tavsifi(x):
        return f"{type(x).__name__}={x}"
    kalit_tavsifi(1); kalit_tavsifi(True)

5.  class Eksport:
        @classmethod
        @functools.singledispatchmethod
        def yoz(cls, x): ...
Javoblar
python
1.  _natijalar, _qulflar = {}, {}
    async def foydalanuvchi(id_):
        if id_ in _natijalar:
            return _natijalar[id_]
        async with _qulflar.setdefault(id_, asyncio.Lock()):
            if id_ not in _natijalar:
                _natijalar[id_] = await db.ol(id_)
        return _natijalar[id_]

2.  class Model:
        __slots__ = ("vaznlar", "__dict__")          # yoki cached_property o'rniga
        @functools.cached_property                   # oddiy metod + lru_cache
        def norma(self):
            return hisobla(self.vaznlar)

3.  @serializatsiya.register
    def _(x: Collection): ...                        # yoki list va tuple uchun aniq realizatsiyalar

4.  @functools.lru_cache(typed=True)
    def kalit_tavsifi(x):
        return f"{type(x).__name__}={x}"

5.  class Eksport:
        @functools.singledispatchmethod
        @classmethod
        def yoz(cls, x): ...

Vazifa 3: Muddatli kesh dekoratori

@ttl_kesh(soniya=60, maxsize=256) dekoratorini yozing:

  1. lru_cache ustida — vaqt oynasi kalitga qo'shilsin (Misol 4 g'oyasi)
  2. hozir funksiyasini sozlash mumkin bo'lsin (testlar uchun)
  3. cache_info() va cache_clear() ishlasin, wraps bilan metama'lumot saqlansin
  4. Kalit bo'yicha qulf bilan stampede himoyasi
  5. async def funksiyalar uchun alohida variant

Vazifa 4: Tur bo'yicha JSON serializatori

singledispatch bilan jsonga(x):

  1. int, float, str, bool, None, Decimal, date, datetime (ISO, aware UTC)
  2. Mapping va Sequence — rekursiv (str ni ketma-ketlik deb olmang!)
  3. dataclass lar — dataclasses.asdict orqali
  4. Noma'lum tur — TypeError aniq xabar bilan
  5. Noaniq tanlov holatlarini dispatch() bilan testlang

Vazifa 5: O'zbek alifbosi bo'yicha lug'at

  1. Misol 3 dagi kalitni kengaytiring: katta harflar, ʼ (tutuq belgisi), defis
  2. 500 ta so'zni saralang va key hamda cmp_to_key tezligini solishtiring
  3. lru_cache bilan kalit hisoblashni keshlash foyda beradimi — o'lchang
  4. Natijani rasmiy imlo lug'ati tartibi bilan solishtiring

Vazifa 6: functools vositalarini o'zingiz yozing

  1. mening_partial — func, args, keywords atributlari bilan
  2. mening_lru_cache(maxsize) — OrderedDict asosida (15.7)
  3. mening_singledispatch — faqat aniq tur va MRO bo'yicha (ABC siz)
  4. mening_total_ordering — __lt__ va __eq__ dan qolganlari
  5. Har biri uchun asl bilan solishtiruvchi testlar

Vazifa 7: O'ylash

Python 3.12 da cached_property ichidagi qulf olib tashlandi. Avval u sinf darajasidagi bitta qulf edi: bir obyektning xususiyati hisoblanayotganda, boshqa obyektlarning ham shu xususiyati kutib turardi. Nega bu qaror qabul qilindi va "ip-xavfsizlik" kafolatini olib tashlash qachon to'g'ri muhandislik qarori bo'ladi?

Javob

Qisqa javob: Qulf noto'g'ri darajada edi: u ip-xavfsizlikni ta'minlash o'rniga barcha obyektlar orasida keraksiz raqobat yaratardi — ko'p ipli dasturlarda sekinlik va hatto blokirovkaga olib kelardi. Kafolat faqat qisman ishlagani uchun uni olib tashlab, zarur joyda ilova darajasida aniq qulf qo'yish tavsiya qilindi. Noto'g'ri yoki qimmat kafolat — kafolatsizlikdan yomonroq bo'lishi mumkin.

1. Eski dizaynning muammosi

Muammo Tafsilot
Sinf darajasidagi qulf A() va B() — ikki xil obyekt, lekin biri hisoblanayotganda ikkinchisi kutadi
Parallellik yo'qoladi 100 ta so'rov, har biri o'z obyekti — ketma-ket bajariladi
Blokirovka xavfi Hisoblash ichida boshqa cached_property ga murojaat qilinsa
Kafolat to'liq emas edi __set_name__ va meros bilan chegaraviy holatlar

2. Nega olib tashlandi

  1. Ko'p ipli ilovalarda (veb-serverlar) haqiqiy sekinlik haqida xabarlar
  2. Obyekt darajasidagi qulf qo'shish — har obyektga xotira narxi va murakkablik
  3. Aksariyat foydalanish holatlari bir ipli — qulf ular uchun ortiqcha narx
  4. Takroriy hisoblash odatda zararsiz (sof funksiya) — faqat vaqt yo'qoladi
  5. Zararli holatlar (tashqi resurs, yon ta'sir) — ilova qulfni o'zi qo'yishi aniqroq

3. Kafolatni olib tashlash qachon to'g'ri

Belgi Izoh
Kafolat ko'pchilik uchun keraksiz narx Oddiy holatni sekinlashtiradi
Kafolat to'liq emas Foydalanuvchini noto'g'ri ishonchga soladi
To'g'ri daraja ilovaga ma'lum Kutubxona uni taxmin qila olmaydi
Muqobil oson Aniq qulf — bir necha qator
Hujjatlashtirilgan O'zgarish "What's New" da e'lon qilingan

4. O'xshash qarorlar

  • lru_cache hech qachon "bir marta bajarish"ni kafolatlamagan — faqat ichki tuzilma butunligini
  • dict amallari GIL tufayli atomar, lekin "o'qish → o'zgartirish → yozish" emas (14.3-dars)
  • Free-threading (3.13t) davrida bunday kafolatlar yana qayta ko'rib chiqilmoqda

5. Amaliy xulosa

  1. Standart kutubxona vositasining konkurentlik kafolatini hujjatdan tekshiring
  2. Takroriy hisoblash zararsizmi? — ha bo'lsa, qulf kerak emas
  3. Zararli bo'lsa (API limiti, pul, yon ta'sir) — kalit yoki obyekt darajasidagi o'z qulfingiz
  4. O'z kutubxonangizda: yarim kafolatdan ko'ra aniq hujjatlashtirilgan "kafolat yo'q" yaxshiroq

Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.


Xulosa

Bu darsda functools modulini yakuniy xarita sifatida ko'rib chiqdik va konkurentlik bilan bog'liq nozik joylarni o'lchadik.

Eng muhim uch fikr:

  1. Kesh va konkurentlik. @cache ni async def ga qo'yish korutina obyektini keshlaydi — ikkinchi await RuntimeError beradi; to'g'ri yo'l — natijani saqlash va asyncio.Lock. lru_cache natija butunligini kafolatlaydi, lekin bo'sh keshda bir vaqtdagi chaqiruvlar funksiyani bir necha marta bajaradi (stampede) — tashqi resurs uchun kalit bo'yicha qulf kerak. cached_property 3.12 dan beri qulfsiz va __slots__ bilan ishlamaydi. Natija argument turiga bog'liq bo'lsa — typed=True.

  2. singledispatch — MRO va ABC. Yuborish sinf ierarxiyasi va ABC lar bo'yicha ishlaydi: bool int realizatsiyasini oladi, int | float ikkala turni ro'yxatga oladi. Lekin teng darajada mos ABC lar (Sized va Iterable) oddiy list da ham RuntimeError beradi — umumiyroq Collection yoki aniq tur bilan hal qilinadi; dispatch() tanlovni oldindan tekshirish imkonini beradi.

  3. Vositalar birgalikda. total_ordering qulay, lekin yasalgan metodlar sekinroq; cmp_to_key faqat kalit yasab bo'lmaganda (eng katta son masalasi), aks holda key — masalan, o'zbek alifbosi bo'yicha saralash; reduce — lug'atlarni birlashtirish va funksiyalar kompozitsiyasi uchun. Valyuta xizmati misolida bularning hammasi partial, wraps va muddatli lru_cache bilan bitta tizimga birlashdi.

Keyingi darsda os va sys modullariga o'tamiz: muhit o'zgaruvchilari, jarayon ma'lumotlari, buyruq qatori argumentlari va platformalar orasidagi farqlar.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
15.10-dars: functools to'liq — IlmHamroh