aidoc.uz

1-qism · Poydevor·04-bob

Boshqaruv oqimi: shartlar, sikllar va pattern matching

if/elif/else, mantiqiy operatorlarning qisqa tutashuvi, for va while sikllari, range, enumerate, zip, break/continue/else, match-case va walrus operatori.

Dastur — bu qarorlar va takrorlashlar. Bu bobda Python'da kod oqimini boshqarishning barcha vositalarini ko'ramiz — va eng muhimi, ularni "pythonic" uslubda, ya'ni Python dasturchilari kutganidek yozishni o'rganamiz. Boshqa tildan kelganlar ko'pincha Python'da C uslubida yozadi (for i in range(len(lst))) — bu ishlaydi, lekin professional ko'rinmaydi.

▶ Video dars· Corey Schafer· 10:14· ingliz tilida
Python Tutorial for Beginners 7: Loops and Iterations - For/While Loops

for va while sikllari, break/continue, range bilan ishlash. match-case va walrus operatori videoda yo'q — ular bobning 6–7-bo'limlarida.

YouTube'da ochish ↗

1. if, elif, else#

ball = 78
 
if ball >= 90:
    baho = "A"
elif ball >= 75:
    baho = "B"
elif ball >= 60:
    baho = "C"
else:
    baho = "F"
 
print(baho)   # B

Shartlar yuqoridan pastga tekshiriladi va birinchi to'g'ri kelganida to'xtaydi. Shuning uchun tartib muhim: ball >= 60ni birinchi yozsangiz, 78 ham "C" bo'lib qoladi.

Taqqoslash operatorlari#

OperatorMa'no
==, !=Teng, teng emas
<, <=, >, >=Katta-kichik
is, is notBitta obyektmi (faqat None uchun)
in, not inIchida bormi

Zanjirli taqqoslash — Python'ning chiroyli xususiyati:

if 0 <= x < 10:          # 0 <= x and x < 10 bilan bir xil
    ...
if a == b == c:          # uchalasi teng
    ...

Shartli ifoda (ternary)#

holat = "kattalar" if yosh >= 18 else "bolalar"

Qisqa holatlar uchun yaxshi. Lekin ichma-ich ternary yozmang — a if x else b if y else c o'qilmaydi; oddiy if/elif ishlating.

2. Mantiqiy operatorlar: and, or, not#

if yosh >= 18 and hujjat_bor:
    ...
if is_admin or is_owner:
    ...
if not ruxsat:
    ...

Qisqa tutashuv (short-circuit)#

Python mantiqiy ifodani faqat natija aniq bo'lguncha hisoblaydi:

  • A and B — agar A yolg'on bo'lsa, B umuman hisoblanmaydi;
  • A or B — agar A rost bo'lsa, B hisoblanmaydi.

Bu xatodan himoyalanish uchun ishlatiladi:

if lst and lst[0] > 0:        # lst bo'sh bo'lsa, lst[0] chaqirilmaydi — IndexError yo'q
    ...
if user is not None and user.is_active:
    ...

and / or qiymat qaytaradi, bool emas#

Bu ko'pchilik bilmaydigan nozik tomon:

>>> 0 or "standart"
'standart'          # birinchi truthy qiymat
>>> "" or None or []
[]                  # hammasi falsy — oxirgisi qaytadi
>>> 5 and "salom"
'salom'             # hammasi truthy — oxirgisi
>>> 0 and "salom"
0                   # birinchi falsy

Shuning uchun ism = kiritilgan or "Mehmon" ishlaydi. Lekin 2-bobda aytilganidek, 0 yoki "" haqiqiy qiymat bo'lishi mumkin bo'lsa, or ishlatmang.

Ustunlik tartibi#

not > and > or. a or b and c → a or (b and c). Shubha bo'lsa — qavs qo'ying. Qavslar o'qilishni yaxshilaydi va hech narsaga zarar qilmaydi.

3. for sikli — iteratsiya, hisoblagich emas#

Python'ning for sikli C'dagi for (i=0; i<n; i++) emas. U har qanday iterable (ro'yxat, satr, lug'at, fayl, generator...) elementlarini birma-bir oladi:

mevalar = ["olma", "nok", "uzum"]
for meva in mevalar:
    print(meva)
 
for harf in "salom":
    print(harf)

range — sonlar ketma-ketligi#

range(5)          # 0, 1, 2, 3, 4
range(2, 6)       # 2, 3, 4, 5
range(0, 10, 3)   # 0, 3, 6, 9
range(5, 0, -1)   # 5, 4, 3, 2, 1

range xotirada ro'yxat yaratmaydi — u "dangasa" (lazy): range(10**12) bir zumda yaratiladi va bir necha bayt egallaydi. Sonlar faqat so'ralganda hisoblanadi.

enumerate — indeks kerak bo'lsa#

# ❌ C uslubi — ko'proq kod, ko'proq xato ehtimoli
for i in range(len(mevalar)):
    print(i, mevalar[i])
 
# ✅ Pythonic
for i, meva in enumerate(mevalar):
    print(i, meva)
 
for i, meva in enumerate(mevalar, start=1):   # 1 dan sanash
    print(f"{i}. {meva}")

zip — bir nechta ketma-ketlikni parallel aylanish#

ismlar = ["Ali", "Vali", "Gani"]
ballar = [85, 92, 78]
 
for ism, ball in zip(ismlar, ballar):
    print(f"{ism}: {ball}")

zip eng qisqa ketma-ketlik tugaganda to'xtaydi — jim. Bu ML'da xavfli: agar predictions va labels uzunligi farq qilsa, xato chiqmaydi, shunchaki ba'zi elementlar tashlab yuboriladi. Python 3.10+ da strict=True qo'shing:

for pred, label in zip(predictions, labels, strict=True):   # uzunlik farq qilsa — ValueError
    ...

Lug'at bo'ylab aylanish#

narxlar = {"olma": 12000, "nok": 15000}
 
for meva in narxlar:                    # kalitlar
    ...
for narx in narxlar.values():           # qiymatlar
    ...
for meva, narx in narxlar.items():      # juftliklar — eng ko'p ishlatiladi
    print(f"{meva}: {narx:,} so'm")

Teskari va saralangan tartibda#

for x in reversed(lst):         # teskari (nusxa yaratmaydi)
    ...
for x in sorted(lst):           # saralangan (yangi ro'yxat)
    ...
for ism in sorted(ballar, key=ballar.get, reverse=True):   # lug'atni qiymat bo'yicha
    ...

Aylanish paytida ro'yxatni o'zgartirmang#

sonlar = [1, 2, 3, 4, 5, 6]
for x in sonlar:
    if x % 2 == 0:
        sonlar.remove(x)        # XAVFLI: indekslar siljiydi, ba'zi elementlar o'tkazib yuboriladi

To'g'ri yo'l — yangi ro'yxat yaratish:

sonlar = [x for x in sonlar if x % 2 != 0]

Lug'atni aylanish paytida kalit qo'shsangiz/o'chirsangiz, Python darhol RuntimeError: dictionary changed size during iteration beradi. Yechim: for k in list(d): — kalitlar nusxasi bo'ylab aylaning.

4. while sikli#

Shart rost ekan, takrorlaydi. Qachon tugashi oldindan ma'lum bo'lmaganda ishlatiladi:

urinish = 0
while urinish < 3:
    javob = input("Parol: ")
    if javob == "maxfiy":
        print("Kirdingiz")
        break
    urinish += 1
else:
    print("Urinishlar tugadi")

Retry — AI muhandisining kundalik sikli#

API chaqiruvlari ba'zan muvaffaqiyatsiz bo'ladi (tarmoq, limit). Klassik "exponential backoff" sikli:

import random
import time
 
 
def call_with_retry(fn, max_attempts: int = 5):
    delay = 1.0
    attempt = 1
    while True:
        try:
            return fn()
        except ConnectionError:
            if attempt == max_attempts:
                raise                      # urinishlar tugadi — xatoni yuqoriga uzatamiz
            sleep_for = delay + random.uniform(0, delay)   # jitter — hamma bir vaqtda qayta urinmasin
            print(f"{attempt}-urinish muvaffaqiyatsiz, {sleep_for:.1f}s kutamiz")
            time.sleep(sleep_for)
            delay *= 2                     # 1, 2, 4, 8...
            attempt += 1

try/except 10-bobda, dekorator ko'rinishi 14-bobda. (Amalda Anthropic va OpenAI SDK'lari retry'ni o'zi qiladi — lekin mexanizmni tushunish kerak.)

Cheksiz sikl xavfi#

i = 0
while i < 10:
    print(i)
    # i += 1 unutildi → cheksiz sikl. Ctrl+C bilan to'xtating.

Agar sikl hisoblagich bilan bo'lsa — for + range ishlating, unda bu xato bo'lmaydi.

5. break, continue va sikldagi else#

  • break — sikldan darhol chiqish;
  • continue — joriy iteratsiyani tashlab, keyingisiga o'tish;
  • else (sikl bilan) — sikl breaksiz tugasa bajariladi.
for qator in fayl_qatorlari:
    qator = qator.strip()
    if not qator or qator.startswith("#"):
        continue                    # bo'sh va izoh qatorlarini o'tkazib yuborish
    qayta_ishlash(qator)

for...else — "topilmadi" holati uchun ideal:

def birinchi_tub_bo_luvchi(n: int) -> int | None:
    for d in range(2, int(n ** 0.5) + 1):
        if n % d == 0:
            break
    else:
        return None     # sikl break'siz tugadi → bo'luvchi topilmadi, n tub
    return d
 
print(birinchi_tub_bo_luvchi(91))   # 7
print(birinchi_tub_bo_luvchi(97))   # None

6. match / case — strukturaviy pattern matching#

Python 3.10'da qo'shilgan. Bu boshqa tillardagi switch emas — u ancha kuchli: ma'lumot shaklini tekshiradi va qismlarini ajratib oladi.

Oddiy qiymatlar#

def http_status(code: int) -> str:
    match code:
        case 200 | 201:
            return "OK"
        case 400:
            return "Noto'g'ri so'rov"
        case 401 | 403:
            return "Ruxsat yo'q"
        case 429:
            return "Juda ko'p so'rov — kuting"
        case _:                           # qolgan hammasi (default)
            return "Noma'lum"

Shakl bo'yicha moslash va ajratib olish#

Bu yerda match haqiqiy kuchini ko'rsatadi. LLM API'lari turli tipdagi "bloklar" qaytaradi — ularni qayta ishlash uchun ideal:

def render(block: dict) -> str:
    match block:
        case {"type": "text", "text": str(matn)}:
            return matn
        case {"type": "tool_use", "name": nom, "input": dict(args)}:
            return f"[asbob chaqirildi: {nom}({', '.join(args)})]"
        case {"type": "image", "source": {"media_type": mt}}:
            return f"[rasm: {mt}]"
        case {"type": tip}:
            return f"[noma'lum blok: {tip}]"
        case _:
            raise ValueError(f"Blok emas: {block!r}")
 
 
print(render({"type": "text", "text": "Salom!"}))
print(render({"type": "tool_use", "name": "get_weather", "input": {"city": "Toshkent", "unit": "C"}}))
print(render({"type": "image", "source": {"media_type": "image/png", "data": "..."}}))
Salom!
[asbob chaqirildi: get_weather(city, unit)]
[rasm: image/png]

E'tibor bering:

  • lug'at pattern'i {"type": "text", ...} — lug'atda kamida shu kalitlar bo'lsa mos keladi (qo'shimcha kalitlar e'tiborsiz);
  • str(matn) — qiymat str tipida bo'lsa, uni matn nomiga bog'laydi;
  • nom kabi oddiy nom — "har qanday qiymatni ushla va shu nomga bog'la".

Ketma-ketlik pattern'lari va shartlar (guard)#

def buyruq(qator: str) -> str:
    match qator.split():
        case ["chiq"] | ["exit"]:
            return "Xayr!"
        case ["salom", ism]:
            return f"Salom, {ism}!"
        case ["qo'sh", *sonlar] if all(s.isdigit() for s in sonlar):
            return str(sum(int(s) for s in sonlar))
        case ["qo'sh", *_]:
            return "Faqat sonlarni qo'shaman"
        case []:
            return ""
        case _:
            return "Tushunmadim"
 
 
print(buyruq("salom Aziz"))    # Salom, Aziz!
print(buyruq("qo'sh 2 3 5"))   # 10
print(buyruq("qo'sh 2 uch"))   # Faqat sonlarni qo'shaman

7. Walrus operatori :=#

Python 3.8+. Ifoda ichida qiymat tayinlaydi va uni qaytaradi:

# Walrus'siz:
qator = f.readline()
while qator:
    qayta_ishlash(qator)
    qator = f.readline()
 
# Walrus bilan:
while (qator := f.readline()):
    qayta_ishlash(qator)
import re
 
if (m := re.search(r"(\d+) ta", matn)) is not None:
    soni = int(m.group(1))

Foydali, lekin ortiqcha ishlatmang — maqsad o'qilishni yaxshilash.

8. pass, ... va bo'sh bloklar#

Python bo'sh blokka ruxsat bermaydi. "Hozircha hech narsa" uchun:

def keyinroq_yozaman():
    pass          # yoki ...
 
class MaxsusXato(Exception):
    pass
 
if shart:
    ...           # Ellipsis — "bu yer hali tayyor emas" ma'nosida ko'p ishlatiladi

9. Amaliyot: oddiy "chatbot" sikli#

Hamma narsani birlashtiramiz — LLM chatbot'ning skeleti (model o'rniga oddiy qoidalar):

def javob_ber(xabar: str) -> str:
    match xabar.lower().split():
        case []:
            return "Biror narsa yozing."
        case ["salom", *_] | ["assalomu", *_]:
            return "Va alaykum assalom! Qanday yordam bera olaman?"
        case [*_, "narx"] | [*_, "narxi"]:
            return "Narxlar haqida ma'lumot uchun /narxlar buyrug'ini yozing."
        case _:
            return "Kechirasiz, tushunmadim. Boshqacha yozib ko'ring."
 
 
def main() -> None:
    print("Chatbot. Chiqish uchun 'chiq' deb yozing.")
    tarix: list[tuple[str, str]] = []
    while True:
        try:
            xabar = input("Siz: ").strip()
        except (EOFError, KeyboardInterrupt):    # Ctrl+D / Ctrl+C
            print()
            break
        if xabar.lower() in {"chiq", "exit", "quit"}:
            break
        javob = javob_ber(xabar)
        tarix.append((xabar, javob))
        print(f"Bot: {javob}")
 
    print(f"Suhbat tugadi. {len(tarix)} ta xabar almashildi.")
 
 
if __name__ == "__main__":
    main()

23-bobda javob_ber ichini haqiqiy Claude API chaqiruvi bilan almashtiramiz va tarix modelga kontekst sifatida yuboriladi.

Nima noto'g'ri ketishi mumkin#

HolatNatijaTo'g'risi
if x = 5:SyntaxErrorif x == 5:
elif tartibi noto'g'riKengroq shart torroqni "yutadi"Torroq shartlarni yuqoriga
for i in range(len(lst))Ishlaydi, lekin pythonic emasenumerate(lst)
zip uzunliklari farq qiladiElementlar jim tashlanadizip(..., strict=True)
Aylanish paytida list.removeElementlar o'tkazib yuboriladiYangi ro'yxat yoki list(...) nusxasi bo'ylab
while ichida hisoblagich unutilganCheksiz siklfor + range
case KONSTANTA:Hamma narsani ushlaydicase Klass.KONSTANTA:
if x == True:Ishlaydi, lekin ortiqchaif x:
if len(lst) == 0:Ishlaydi, lekin ortiqchaif not lst:
Amaliy topshiriq

1. FizzBuzz — lekin to'g'ri

1 dan 100 gacha sonlarni chiqaring: 3 ga bo'linsa "Fizz", 5 ga — "Buzz", ikkalasiga — "FizzBuzz". Ikki xil yechim yozing: if/elif bilan va match (n % 3, n % 5): bilan.

Maslahatni ko'rsatish

15 ga bo'linishni birinchi tekshiring yoki satrni yig'ib boring: s = ''; if n % 3 == 0: s += 'Fizz' ...

Amaliy topshiriq

2. Accuracy va xatolar ro'yxati

preds = [1, 0, 1, 1, 0, 1] va labels = [1, 0, 0, 1, 0, 0] berilgan. Accuracy'ni (to'g'ri bashoratlar ulushi) hisoblang va noto'g'ri bashorat qilingan indekslar ro'yxatini chiqaring. Uzunliklar farq qilsa, kod xato berishi kerak.

Maslahatni ko'rsatish

zip(preds, labels, strict=True) va enumerate'ni birga ishlating: for i, (p, y) in enumerate(zip(...)).

Amaliy topshiriq

3. API javobini qayta ishlash

Quyidagi "model javobi"dan barcha matnli bloklarni birlashtirib, chaqirilgan asboblar nomlarini alohida ro'yxatga ajratib oling (match ishlating):

content = [
    {"type": "thinking", "thinking": "..."},
    {"type": "text", "text": "Ob-havoni tekshiraman."},
    {"type": "tool_use", "id": "t1", "name": "get_weather", "input": {"city": "Samarqand"}},
    {"type": "text", "text": "Bir daqiqa."},
]
Maslahatni ko'rsatish

Har bir blok uchun match block: case {'type': 'text', 'text': t}: ... Natijalarni ro'yxatga yig'ib, oxirida join qiling.

Amaliy topshiriq

4. Retry'ni sinash

call_with_retryni sinash uchun soxta funksiya yozing: u birinchi 3 marta ConnectionError ko'tarsin, 4-chi marta "OK" qaytarsin. (Maslahat: hisoblagichni ro'yxatda saqlang: holat = [0], funksiya ichida holat[0] += 1.) max_attempts=3 bilan chaqirsangiz nima bo'ladi?

Yodda saqlang
  • 01if/elif yuqoridan pastga, birinchi mos kelganda to'xtaydi; zanjirli taqqoslash: 0 <= x < 10.
  • 02and/or qisqa tutashadi va bool emas, operand qiymatini qaytaradi.
  • 03for — iterable bo'ylab aylanish; indeks uchun enumerate, parallel uchun zip(..., strict=True).
  • 04Aylanish paytida to'plamni o'zgartirmang — yangisini yarating.
  • 05while — tugash nuqtasi noma'lum bo'lganda; retry va backoff — AI kodining kundalik sikli.
  • 06for/while ... else — 'nobreak': sikl break'siz tugasa ishlaydi.
  • 07match/case — qiymat emas, shakl bo'yicha moslaydi va qismlarni ajratib oladi; oddiy nom hamma narsani ushlaydi.
  • 08Walrus := ifoda ichida tayinlaydi — o'qilishni yaxshilasa ishlating.

Mustahkamlash

Test va amaliy masalalar

Avval testni ishlang — har javobdan keyin izoh chiqadi. Keyin masalalarni shu yerning o'zida yechib, brauzerdagi haqiqiy Python bilan avtomatik tekshiring. Natijalaringiz kurs progressi sahifasida jamlanadi.

Test: topshirilmaganMasalalar: 0/3

Bilimni tekshirish

Bob bo'yicha test

12 ta savol · har javobdan keyin to'g'ri yoki xatoligi va izoh ko'rsatiladi · oxirida natija foizda.

Amaliy masalalar

Kodni yozing va «Tekshirish»ni bosing (yoki Ctrl/⌘ + Enter). Kodingiz shu brauzerda saqlanib turadi.

01FizzBuzz ro'yxati

fizzbuzz(n) 1 dan n gacha elementlar ro'yxatini qaytarsin: 3 ga bo'linsa "Fizz", 5 ga — "Buzz", ikkalasiga — "FizzBuzz", aks holda sonning o'zi (int).

02Accuracy va xato indekslar

evaluate(preds, labels) → (accuracy, xato_indekslar) qaytarsin. Uzunliklar farq qilsa ValueError bo'lsin (zip(..., strict=True) ishlating). evaluate([1,0,1,1], [1,0,0,1]) → (0.75, [2]).

03Blok renderer (match)

render(block) — LLM javob bloklarini match bilan qayta ishlasin:

  • {"type": "text", "text": t} → t
  • {"type": "tool_use", "name": n, ...} → "[tool: n]"
  • boshqa har qanday {"type": x, ...} → "[x]"