OzbekPython / Bob 11

Funksiyalar

Kodni qayta işlatiş — def, parametrlar, return, *args/**kwargs, köriniş sohasi, lambda va sof funksiyalar.

Boşlanğiç daraja19 daqiqa19 kod misoli11 / 24

Nega funksiyalar kerak?

Tasavvur qiling, dasturingizning beş joyida narxga QQS (12%) qöşib, çiroyli formatda çiqariş kerak. Har safar şu hisobni qayta yozsangiz, ertaga QQS stavkasi özgarganda beş joyni topib tuzatişingiz kerak böladi — bittasini unutib qöyiş oson.

Funksiya — nom berilgan kod bölagi. Uni bir marta yozasiz va keyin istalgança çaqirasiz. Funksiyalar:

  • takrorlanişni yöqotadi (bir joyda tuzatiş — hamma joyda tuzaladi);
  • katta masalani kiçik, tuşunarli qismlarga böladi;
  • kodni öqişni osonlaştiradi: qqs_qosh(narx) nomi özi nima qilişini aytib turadi.

Siz allaqaçon köp funksiyadan foydalangansiz: print(), len(), input(). Endi özimiznikini yozamiz.

def bilan funksiya yaratiş

Python
def salomlash():
    print("Assalomu alaykum!")
    print("Darsimizga xuş kelibsiz.")

salomlash()
salomlash()

Natija:

Natija
Assalomu alaykum!
Darsimizga xuş kelibsiz.
Assalomu alaykum!
Darsimizga xuş kelibsiz.

def kalit sözi, funksiya nomi, qavslar va ikki nuqta — bu eʼlon qiliş. Surilgan qatorlar funksiya tanasi. Eʼlon qilinganda kod bajarilmaydi, faqat çaqirilganda (salomlash()) işlaydi. Qavslarsiz salomlash yozsangiz, funksiya çaqirilmaydi — bu keng tarqalgan xato.

Parametrlar va argumentlar

Funksiyaga maʼlumot uzatiş mumkin. Eʼlondagi nomlar — parametrlar, çaqirganda beriladigan haqiqiy qiymatlar — argumentlar:

Python
def tabrikla(ism, yosh):          # ism, yoş - parametrlar
    print(f"{ism}, {yosh} yoşingiz bilan tabriklaymiz!")

tabrikla("Madina", 21)            # "Madina", 21 - argumentlar
tabrikla("Otabek", 30)

Natija:

Natija
Madina, 21 yoşingiz bilan tabriklaymiz!
Otabek, 30 yoşingiz bilan tabriklaymiz!

Standart qiymatlar va kalitli argumentlar

Parametrga standart qiymat bersangiz, u argumentni beriş ixtiyoriy böladi. Çaqirganda esa argumentlarni nomi bilan (keyword argument) ham beriş mumkin — şunda tartib muhim emas:

Python
def kofe_buyurt(nom, hajm="örta", shakar=0):
    print(f"{nom}: {hajm} hajm, {shakar} qoşiq şakar")

kofe_buyurt("Latte")
kofe_buyurt("Kapuçino", "katta")
kofe_buyurt("Amerikano", shakar=2)
kofe_buyurt(shakar=1, nom="Raf")

Natija:

Natija
Latte: örta hajm, 0 qoşiq şakar
Kapuçino: katta hajm, 0 qoşiq şakar
Amerikano: örta hajm, 2 qoşiq şakar
Raf: örta hajm, 1 qoşiq şakar

*args va **kwargs

Baʼzan argumentlar soni oldindan nomaʼlum böladi. *args barça qöşimça oddiy argumentlarni kortejga, **kwargs esa barça qöşimça nomli argumentlarni luğatga yiğadi (nomlar ixtiyoriy, muhimi * va **):

Python
def jami_narx(*narxlar):
    print("Kelgan narxlar:", narxlar)
    return sum(narxlar)

print(jami_narx(4000, 12000, 18000))

def profil(ism, **malumot):
    print(f"Foydalanuvçi: {ism}")
    for kalit, qiymat in malumot.items():
        print(f"  {kalit}: {qiymat}")

profil("Javlon", shahar="Namangan", kasb="dasturçi")

Natija:

Natija
Kelgan narxlar: (4000, 12000, 18000)
34000
Foydalanuvçi: Javlon
  shahar: Namangan
  kasb: dasturçi

return: qiymat qaytariş

print() natijani faqat ekranga çiqaradi. return esa natijani funksiyadan qaytaradi — uni özgaruvçiga yoziş, boşqa hisobda işlatiş mumkin:

Python
def qqs_qosh(narx, stavka=0.12):
    return round(narx * (1 + stavka), 2)

narx = qqs_qosh(50000)
print(narx)
print(qqs_qosh(10000) + qqs_qosh(20000))

def hech_narsa():
    x = 5

print(hech_narsa())

Natija:

Natija
56000.0
33600.0
None

return bölmagan funksiya avtomatik ravişda None qaytaradi.

Bir neçta qiymat va erta qaytiş

return vergul bilan bir neçta qiymat qaytara oladi (aslida bitta kortej). return bajarilişi bilan funksiya darhol tugaydi — bundan notöğri holatlarni boşidayoq "çiqarib yuboriş" uçun foydalaniladi:

Python
def statistika(ballar):
    if not ballar:                  # erta qaytiş
        return None
    return min(ballar), max(ballar), sum(ballar) / len(ballar)

eng_kam, eng_kop, ortacha = statistika([72, 95, 88, 64])
print(eng_kam, eng_kop, ortacha)
print(statistika([]))

Natija:

Natija
64 95 79.75
None

Docstring va tur izohlari

Funksiya nima qilişini uning birinçi qatoriga uçta qöştirnoq içida yoziş odat tusiga kirgan. Bu docstring deyiladi va help() orqali körinadi. Tur izohlari (type hints) esa parametr va natija qanday turda ekanini bildiradi:

Python
def kurs_bilan(summa_usd: float, kurs: float = 12_800) -> float:
    """Dollardagi summani sömga ögiradi."""
    return summa_usd * kurs

print(kurs_bilan(25))
print(kurs_bilan.__doc__)

Natija:

Natija
320000
Dollardagi summani sömga ögiradi.

Köriniş sohasi (scope)

Funksiya içida yaratilgan özgaruvçi — lokal, u faqat şu funksiya içida mavjud. Fayl darajasida yaratilgani — global:

Python
shahar = "Toşkent"        # global

def sayohat():
    shahar = "Samarqand"   # lokal, global özgaruvçiga tegmaydi
    print("Içkarida:", shahar)

sayohat()
print("Taşqarida:", shahar)

Natija:

Natija
Içkarida: Samarqand
Taşqarida: Toşkent

Global özgaruvçini funksiya içida özgartiriş kerak bölsa, global kalit sözi işlatiladi. Içma-iç funksiyada taşqi funksiyaning özgaruvçisini özgartiriş uçun esa nonlocal:

Python
tashriflar = 0

def tashrif_qosh():
    global tashriflar
    tashriflar += 1

tashrif_qosh()
tashrif_qosh()
print("Taşriflar:", tashriflar)

def hisoblagich_yarat():
    son = 0
    def keyingi():
        nonlocal son
        son += 1
        return son
    return keyingi

navbat = hisoblagich_yarat()
print(navbat(), navbat(), navbat())

Natija:

Natija
Taşriflar: 2
1 2 3

lambda ifodalari

lambda — bitta ifodadan iborat kiçik, nomsiz funksiya. U asosan boşqa funksiyaga "qanday işlaş kerak"ligini qisqa aytiş uçun işlatiladi:

Python
kvadrat = lambda x: x ** 2
print(kvadrat(7))

mahsulotlar = [("non", 4000), ("göşt", 95000), ("sut", 12000)]
mahsulotlar.sort(key=lambda m: m[1])
print(mahsulotlar)

Natija:

Natija
49
[('non', 4000), ('sut', 12000), ('göşt', 95000)]

Birinçi misoldagidek lambdani özgaruvçiga yoziş yaxşi uslub emas — buning uçun oddiy def bor. lambda ikkinçi misoldagi kabi joylarda özini oqlaydi. Bu haqda 12-bobda köproq gaplaşamiz.

Metod va funksiya farqi

Metod — maʼlum bir obyektga "boğlangan" funksiya. U nuqta orqali çaqiriladi va öşa obyekt bilan işlaydi:

Python
ism = "nodira"
print(len(ism))          # funksiya: obyektni argument sifatida oladi
print(ism.upper())       # metod: satr obyektining öziga tegişli

sonlar = [3, 1, 2]
sonlar.append(5)         # röyxat metodi röyxatni özgartiradi
print(sorted(sonlar), sonlar)

Natija:

Natija
6
NODIRA
[1, 2, 3, 5] [3, 1, 2, 5]

len() har xil turdagi obyektlar bilan işlaydi, upper() esa faqat satrlarda bor. Metodlarni özimiz qanday yaratişni sinflar (class) mavzusida örganamiz.

Sof funksiyalar

Sof funksiya (pure function) — natijasi faqat argumentlarga boğliq va taşqi dunyoni özgartirmaydigan funksiya. Bir xil argument — doim bir xil natija:

Python
# Sof emas: taşqi röyxatni özgartiradi
def chegirma_qoy(narxlar):
    for i in range(len(narxlar)):
        narxlar[i] *= 0.9

# Sof: yangi röyxat qaytaradi, asl röyxatga tegmaydi
def chegirmali(narxlar, foiz=10):
    return [n * (100 - foiz) / 100 for n in narxlar]

asl = [10000, 25000]
yangi = chegirmali(asl)
print(asl, yangi)

chegirma_qoy(asl)
print(asl)

Natija:

Natija
[10000, 25000] [9000.0, 22500.0]
[9000.0, 22500.0]

Sof funksiyalarni tekşiriş, qayta işlatiş va xatosini topiş ança oson. Imkon bölsa, funksiyalaringizni şunday yozing.

Amaliyot: tub sonni tekşiriş

Tub son faqat 1 ga va öziga bölinadi. Böluvçilarni √n gaça tekşiriş kifoya, çunki katta böluvçining "jufti" doim kiçik böladi:

Python
def tubmi(n: int) -> bool:
    """n tub son bölsa True qaytaradi."""
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

print([n for n in range(1, 40) if tubmi(n)])
print(tubmi(97), tubmi(91))

Natija:

Natija
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
True False

Amaliyot: böluvçilar

Python
def boluvchilar(n: int) -> list[int]:
    """n ning barça musbat böluvçilarini ösiş tartibida qaytaradi."""
    return [i for i in range(1, n + 1) if n % i == 0]

def mukammalmi(n: int) -> bool:
    """Özidan boşqa böluvçilar yiğindisi öziga tengmi?"""
    return sum(boluvchilar(n)[:-1]) == n

print(boluvchilar(36))
print([n for n in range(2, 1000) if mukammalmi(n)])

Natija:

Natija
[1, 2, 3, 4, 6, 9, 12, 18, 36]
[6, 28, 496]

Eʼtibor bering: mukammalmi() içida boluvchilar() funksiyasidan foydalandik — kiçik funksiyalardan kattasini yiğiş şunday böladi.

Amaliyot: kredit kalkulyatori

Bankda kredit odatda annuitet usulida tölanadi: har oy bir xil summa. Oylik tölov formulasi:

tolov = S * r / (1 - (1 + r) ** -n)

Bu yerda S — kredit summasi, r — oylik foiz stavkasi (yillik stavka / 12), n — oylar soni.

Python
def oylik_tolov(summa: float, yillik_foiz: float, oylar: int) -> float:
    """Annuitet kredit böyiça oylik tölovni hisoblaydi."""
    if yillik_foiz == 0:
        return summa / oylar
    r = yillik_foiz / 100 / 12
    return summa * r / (1 - (1 + r) ** -oylar)

def kredit_hisoboti(summa, yillik_foiz, oylar):
    tolov = oylik_tolov(summa, yillik_foiz, oylar)
    jami = tolov * oylar
    print(f"Kredit: {summa:,.0f} söm, {yillik_foiz}% yillik, {oylar} oy")
    print(f"  Oylik tölov:    {tolov:,.0f} söm")
    print(f"  Jami tölanadi:  {jami:,.0f} söm")
    print(f"  Ortiqça tölov: {jami - summa:,.0f} söm")

kredit_hisoboti(30_000_000, 24, 12)
kredit_hisoboti(30_000_000, 24, 36)

Natija:

Natija
Kredit: 30,000,000 söm, 24% yillik, 12 oy
  Oylik tölov:    2,836,788 söm
  Jami tölanadi:  34,041,455 söm
  Ortiqça tölov: 4,041,455 söm
Kredit: 30,000,000 söm, 24% yillik, 36 oy
  Oylik tölov:    1,176,986 söm
  Jami tölanadi:  42,371,481 söm
  Ortiqça tölov: 12,371,481 söm

Muddat uzaygani sari oylik tölov kamayadi, lekin umumiy ortiqça tölov keskin oşadi — funksiya buni bir qaraşda körsatib berdi.

Xulosa

  • Funksiya def bilan eʼlon qilinadi va faqat çaqirilganda işlaydi.
  • Parametrlar eʼlonda, argumentlar çaqiruvda; standart qiymatlar va kalitli argumentlar çaqiruvni moslaşuvçan qiladi.
  • *args qöşimça argumentlarni kortejga, **kwargs luğatga yiğadi.
  • return natijani qaytaradi (bir neçta qiymatni ham); return siz funksiya None qaytaradi.
  • Docstring va tur izohlari kodni hujjatlaştiradi.
  • Lokal özgaruvçilar funksiya içida yaşaydi; global va nonlocal dan ehtiyotkorlik bilan foydalaning.
  • lambda — qisqa nomsiz funksiya; metod — obyektga boğlangan funksiya; sof funksiyalar eng işonçli.

Maşqlar

  1. Selsiyni Farengeytga ögiruvçi farengeyt(c) funksiyasini yozing (F = C * 9 / 5 + 32) va -10, 0, 36.6 uçun sinang.
Yeçim
Python
def farengeyt(c: float) -> float:
    """Selsiydan Farengeytga ögiradi."""
    return c * 9 / 5 + 32

for c in (-10, 0, 36.6):
    print(f"{c} C = {farengeyt(c):.1f} F")
  1. Istalgança son qabul qilib, ularning örtaçasini qaytaruvçi ortacha(*sonlar) funksiyasini yozing. Son berilmasa 0 qaytarsin.
Yeçim
Python
def ortacha(*sonlar: float) -> float:
    if not sonlar:
        return 0
    return sum(sonlar) / len(sonlar)

print(ortacha(4, 5, 3, 5))
print(ortacha())
  1. Satrda neçta söz, neçta harf va neçta raqam borligini kortej qilib qaytaruvçi funksiya yozing.
Yeçim
Python
def tahlil(matn: str) -> tuple[int, int, int]:
    sozlar = len(matn.split())
    harflar = sum(1 for b in matn if b.isalpha())
    raqamlar = sum(1 for b in matn if b.isdigit())
    return sozlar, harflar, raqamlar

print(tahlil("2025-yilda 3 ta kitob öqidim"))
  1. Berilgan sondan kiçik yoki teng bölgan barça tub sonlar yiğindisini qaytaruvçi funksiya yozing. Bobdagi tubmi() funksiyasidan foydalaning.
Yeçim
Python
def tubmi(n: int) -> bool:
    if n < 2:
        return False
    for i in range(2, int(n ** 0.5) + 1):
        if n % i == 0:
            return False
    return True

def tublar_yigindisi(chegara: int) -> int:
    return sum(n for n in range(2, chegara + 1) if tubmi(n))

print(tublar_yigindisi(10))
print(tublar_yigindisi(100))