2-qism · Ma'lumot tuzilmalari va funksiyalar·05-bob
Ro'yxatlar va tuple'lar
list va tuple qanday ishlaydi, metodlar va ularning tezligi, nusxalash (shallow va deep copy), saralash va key funksiyalari, unpacking va eng ko'p uchraydigan tuzoqlar.
Ro'yxat (list) — Python'da eng ko'p ishlatiladigan ma'lumot tuzilmasi.
Dataset qatorlari, model bashoratlari, chat xabarlari tarixi, fayllar
ro'yxati — hammasi ro'yxat. Tuple esa uning o'zgarmas "egizagi". Bu bobda
ikkalasini ichki ishlashidan tortib professional ishlatilishigacha
ko'ramiz.
Ro'yxatlar, tuple'lar va to'plamlar metodlari amaliy misollarda. Bobdagi nusxalash (shallow va deep copy) qismini alohida diqqat bilan o'qing.
1. Ro'yxat — o'zgaruvchan ketma-ketlik#
bo_sh = []
sonlar = [3, 1, 4, 1, 5]
aralash = [1, "ikki", 3.0, None, [5, 6]] # turli tiplar mumkin (lekin odatda yaxshi g'oya emas)
harflar = list("salom") # ['s', 'a', 'l', 'o', 'm']
juftlar = list(range(0, 10, 2)) # [0, 2, 4, 6, 8]Indekslash va slicing satrlardagidek ishlaydi (3-bob) — farqi shundaki, ro'yxatni o'zgartirish mumkin:
lst = [10, 20, 30, 40, 50]
lst[0] = 99 # [99, 20, 30, 40, 50]
lst[1:3] = [0, 0, 0] # [99, 0, 0, 0, 40, 50] — slice'ni boshqa uzunlikdagi ro'yxat bilan almashtirish
del lst[0] # [0, 0, 0, 40, 50]
del lst[-2:] # [0, 0, 0]Ichki tuzilish: dinamik massiv#
Python ro'yxati — bu bog'langan ro'yxat (linked list) emas, dinamik massiv: xotirada ketma-ket joylashgan obyektlarga ko'rsatkichlar massivi.
Bundan ikkita muhim xulosa:
lst[i]— O(1), ya'ni ro'yxat qanchalik katta bo'lmasin, bir zumda.- Ro'yxat oxiriga qo'shish odatda tez, chunki Python oldindan ortiqcha joy (sig'im) ajratib qo'yadi. Joy tugasa — kattaroq massiv ajratiladi va hamma ko'rsatkichlar ko'chiriladi (lekin bu kamdan-kam bo'ladi, shuning uchun o'rtacha O(1)).
Metodlar va ularning narxi#
| Amal | Misol | Murakkablik | Izoh |
|---|---|---|---|
| Oxiriga qo'shish | lst.append(x) | O(1) | Eng ko'p ishlatiladigan |
| Ko'p element qo'shish | lst.extend(boshqa) | O(k) | lst += boshqa bilan bir xil |
| Oxiridan olish | lst.pop() | O(1) | |
| Boshidan olish | lst.pop(0) | O(n) | Hamma elementlar siljiydi! |
| O'rtaga qo'shish | lst.insert(i, x) | O(n) | |
| Qiymat bo'yicha o'chirish | lst.remove(x) | O(n) | Birinchi uchraganini; yo'q bo'lsa ValueError |
| Qidirish | x in lst, lst.index(x) | O(n) | Har birini tekshiradi |
| Sanash | lst.count(x) | O(n) | |
| Saralash | lst.sort() | O(n log n) | Joyida |
| Teskari | lst.reverse() | O(n) | Joyida |
| Uzunlik | len(lst) | O(1) | Saqlab qo'yilgan |
lst = [3, 1, 2]
lst.append(4) # [3, 1, 2, 4]
lst.extend([5, 6]) # [3, 1, 2, 4, 5, 6]
lst.insert(0, 0) # [0, 3, 1, 2, 4, 5, 6]
oxirgi = lst.pop() # 6, lst = [0, 3, 1, 2, 4, 5]
lst.remove(3) # [0, 1, 2, 4, 5]append va extend farqi:
a = [1, 2]
a.append([3, 4]) # [1, 2, [3, 4]] — ro'yxat BITTA element sifatida
b = [1, 2]
b.extend([3, 4]) # [1, 2, 3, 4]Ro'yxat operatorlari#
[1, 2] + [3] # [1, 2, 3] — yangi ro'yxat
[0] * 4 # [0, 0, 0, 0]
2 in [1, 2, 3] # True
len([1, 2, 3]) # 3
min(lst), max(lst), sum(lst)2. Nusxalash: eng muhim mavzu#
2-bobda b = a nusxa emasligini ko'rdik. Endi nusxalashning ikki turini
farqlaymiz.
Sayoz nusxa (shallow copy)#
a = [1, 2, 3]
b = a.copy() # yoki list(a), yoki a[:]
b.append(4)
print(a) # [1, 2, 3] — a daxlsizLekin ro'yxat ichida mutable obyektlar bo'lsa:
a = [[1, 2], [3, 4]]
b = a.copy()
b[0].append(99) # ichki ro'yxatni o'zgartirish
b.append([5]) # tashqi ro'yxatga qo'shish
print(a) # [[1, 2, 99], [3, 4]] ← ichki o'zgarish ko'rindi!
print(b) # [[1, 2, 99], [3, 4], [5]]Sayoz nusxa faqat tashqi ro'yxatni nusxalaydi — ichidagi havolalar o'sha-o'sha obyektlarga ishora qiladi.
Chuqur nusxa (deep copy)#
import copy
a = [[1, 2], [3, 4]]
c = copy.deepcopy(a) # hamma darajani rekursiv nusxalaydi
c[0].append(7)
print(a) # [[1, 2], [3, 4]] — to'liq daxlsiz| Usul | Tashqi ro'yxat | Ichki obyektlar | Qachon |
|---|---|---|---|
b = a | Umumiy | Umumiy | Hech qachon "nusxa" uchun |
a.copy(), a[:], list(a) | Yangi | Umumiy | Ichida immutable (son, satr) bo'lsa |
copy.deepcopy(a) | Yangi | Yangi | Ichma-ich mutable tuzilmalar (konfiguratsiya, JSON) |
2D ro'yxat tuzog'i#
grid = [[0] * 3] * 3 # 3x3 matritsa... shundaymi?
grid[0][0] = 1
print(grid) # [[1, 0, 0], [1, 0, 0], [1, 0, 0]] ← uchala qator o'zgardi!* 3 ichki ro'yxatni 3 marta nusxalamaydi — bitta ro'yxatga 3 ta havola
yaratadi. To'g'ri usul:
grid = [[0] * 3 for _ in range(3)] # har qator — yangi ro'yxat
grid[0][0] = 1
print(grid) # [[1, 0, 0], [0, 0, 0], [0, 0, 0]](Amalda matritsalar uchun NumPy ishlatiladi: np.zeros((3, 3)) — 19-bob.)
3. Saralash#
Ikki usul:
lst = [3, 1, 2]
yangi = sorted(lst) # yangi ro'yxat qaytaradi, lst o'zgarmaydi; HAR QANDAY iterable'ni qabul qiladi
lst.sort() # joyida saralaydi, None qaytaradi; faqat list uchunkey — saralash mezoni#
key — har bir elementdan "saralash qiymatini" oladigan funksiya:
so_zlar = ["banana", "Olma", "nok", "anor"]
sorted(so_zlar) # ['Olma', 'anor', 'banana', 'nok'] — katta harf oldin!
sorted(so_zlar, key=str.lower) # ['anor', 'banana', 'nok', 'Olma']
sorted(so_zlar, key=len) # ['nok', 'Olma', 'anor', 'banana']
sorted(so_zlar, key=len, reverse=True) # eng uzunidanBir nechta mezon bo'yicha#
key tuple qaytarsa — avval birinchi element, teng bo'lsa ikkinchisi
bo'yicha saralanadi:
talabalar = [("Ali", 85), ("Vali", 92), ("Gani", 85), ("Soli", 70)]
# ball bo'yicha kamayish, teng bo'lsa ism bo'yicha o'sish
sorted(talabalar, key=lambda t: (-t[1], t[0]))
# [('Vali', 92), ('Ali', 85), ('Gani', 85), ('Soli', 70)]lambda — kichik nomsiz funksiya (8-bob). operator.itemgetter tezroq va
ba'zan o'qilishi osonroq:
from operator import itemgetter
sorted(talabalar, key=itemgetter(1), reverse=True)
max(talabalar, key=itemgetter(1)) # ('Vali', 92) — min/max ham key qabul qiladiBarqarorlik (stability). Python'ning saralash algoritmi (Timsort) barqaror: teng elementlar asl tartibini saqlaydi. Shuning uchun murakkab saralashni bosqichma-bosqich qilish mumkin — avval ikkinchi darajali mezon, keyin asosiy mezon bo'yicha.
Saralangan ro'yxatda tez qidirish: bisect#
import bisect
chegaralar = [60, 75, 90] # baho chegaralari
baholar = ["F", "C", "B", "A"]
def baho(ball: int) -> str:
return baholar[bisect.bisect_right(chegaralar, ball)]
print([baho(b) for b in [45, 60, 74, 89, 95]]) # ['F', 'C', 'C', 'B', 'A']bisect ikkilik qidiruv (binary search) — O(log n). Saralangan
ro'yxatga tartibni buzmasdan qo'shish: bisect.insort(lst, x).
4. Tuple — o'zgarmas ketma-ketlik#
nuqta = (3, 4)
rgb = 255, 128, 0 # qavssiz ham tuple
bitta = (5,) # BITTA elementli tuple — vergul shart!
emas = (5) # bu shunchaki int 5
bo_sh = ()(5) — tuple emas, qavs ichidagi son. Tuple'ni vergul yaratadi,
qavs emas.
Nega tuple kerak, list bor-ku?#
| list | tuple | |
|---|---|---|
| O'zgaruvchanlik | Mutable | Immutable |
| Ma'nosi | Bir xil turdagi elementlar to'plami (ro'yxat) | Turli ma'noli maydonlardan iborat yozuv |
| Misol | [85, 92, 78] — ballar | ("Ali", 25, "Toshkent") — bitta odam |
| Lug'at kaliti bo'la oladimi | Yo'q | Ha (ichidagilar ham immutable bo'lsa) |
| Xotira / tezlik | Biroz ko'proq | Biroz kamroq |
Asosiy farq — ma'no. Tuple — "bu narsalar birga bitta yozuvni tashkil
qiladi va o'zgarmaydi" degan signal. Funksiyadan bir nechta qiymat
qaytarish, koordinatalar, lug'at kalitlari, tensor shakllari
(shape = (32, 3, 224, 224)) — hammasi tuple.
def statistika(sonlar: list[float]) -> tuple[float, float, float]:
return min(sonlar), max(sonlar), sum(sonlar) / len(sonlar)
kichik, katta, ortacha = statistika([4, 8, 15, 16, 23, 42])"O'zgarmas" — lekin nisbatan#
t = ([1, 2], 3)
t[0].append(3) # ruxsat! Tuple o'zgarmadi — u hamon o'sha ro'yxatga ishora qiladi
print(t) # ([1, 2, 3], 3)
t[0] = [9] # TypeError — havolani almashtirib bo'lmaydiTuple faqat o'zining havolalarini o'zgarmas qiladi. Ichida ro'yxat bo'lsa — u tuple hash qilinmaydi va lug'at kaliti bo'la olmaydi.
5. Unpacking — ochib tayinlash#
x, y = (3, 4)
ism, yosh, shahar = ["Ali", 25, "Toshkent"]
birinchi, *qolgan = [1, 2, 3, 4] # 1, [2, 3, 4]
*boshi, oxirgi = [1, 2, 3, 4] # [1, 2, 3], 4
bosh, *orta, oxir = range(6) # 0, [1, 2, 3, 4], 5
x, (y, z) = 1, (2, 3) # ichma-ich
for ism, ball in [("Ali", 85), ("Vali", 92)]: # siklda ochish
...
_, ikkinchi, _ = (1, 2, 3) # kerakmas qiymatlar uchun _Elementlar soni mos kelmasa — ValueError: too many values to unpack.
* bilan ochish (spread)#
a = [1, 2]
b = [3, 4]
birlashgan = [*a, *b, 5] # [1, 2, 3, 4, 5]
print(*a) # print(1, 2) — argument sifatida ochishMatritsani transpoze qilish — zip(*...)#
m = [[1, 2, 3],
[4, 5, 6]]
t = [list(qator) for qator in zip(*m)]
# [[1, 4], [2, 5], [3, 6]]zip(*m) — zip([1, 2, 3], [4, 5, 6]) bilan bir xil. Bu hiyla juftliklar
ro'yxatini ikki ro'yxatga ajratishda ham ishlatiladi:
juftlar = [("Ali", 85), ("Vali", 92), ("Gani", 78)]
ismlar, ballar = zip(*juftlar)
# ismlar = ('Ali', 'Vali', 'Gani'), ballar = (85, 92, 78)6. Ro'yxat bilan ishlashning foydali usullari#
lst = [5, 3, 8, 1]
any(x > 7 for x in lst) # True — kamida bittasi
all(x > 0 for x in lst) # True — hammasi
sum(x for x in lst if x > 2) # 16
max(lst, default=None) # bo'sh ro'yxat uchun xato o'rniga default
list(reversed(lst)) # [1, 8, 3, 5]
lst[::-1] # [1, 8, 3, 5]
# Dublikatlarni tartibni saqlab olib tashlash
unikal = list(dict.fromkeys([3, 1, 3, 2, 1])) # [3, 1, 2]
# Ro'yxatni teng bo'laklarga (batch) bo'lish
def batched(items: list, size: int) -> list[list]:
return [items[i:i + size] for i in range(0, len(items), size)]
batched(list(range(7)), 3) # [[0, 1, 2], [3, 4, 5], [6]]Python 3.12'dan boshlab standart kutubxonada itertools.batched bor
(7-bobda ko'ramiz) — u tuple'lar qaytaradi va har qanday iterable bilan
ishlaydi.
7. Amaliyot: chat tarixi#
LLM bilan suhbat — xabarlar ro'yxati. Ko'p qo'llaniladigan amallar:
Message = dict[str, str]
history: list[Message] = [
{"role": "user", "content": "Salom!"},
{"role": "assistant", "content": "Salom! Qanday yordam bera olaman?"},
{"role": "user", "content": "Python nima?"},
{"role": "assistant", "content": "Python — dasturlash tili..."},
]
def add_turn(history: list[Message], user: str, assistant: str) -> list[Message]:
"""Yangi ro'yxat qaytaradi — asl tarix o'zgarmaydi."""
return [*history, {"role": "user", "content": user}, {"role": "assistant", "content": assistant}]
def last_turns(history: list[Message], n: int) -> list[Message]:
"""Oxirgi n ta savol-javob juftligi (kontekst oynasini tejash uchun)."""
return history[-2 * n:] if n > 0 else []
def total_chars(history: list[Message]) -> int:
return sum(len(m["content"]) for m in history)
print(len(last_turns(history, 1)), total_chars(history))E'tibor bering: add_turn asl ro'yxatni o'zgartirmaydi — yangisini
qaytaradi. Bu xatolarni kamaytiradi: masalan, bir xil "boshlang'ich
tarix"dan bir nechta turli suhbat davom ettirsangiz, ular bir-biriga
aralashmaydi.
Nima noto'g'ri ketishi mumkin#
| Holat | Natija | To'g'risi |
|---|---|---|
b = a nusxa deb o'ylash | Ikki nom bitta ro'yxatda | a.copy() |
Ichma-ich tuzilmani .copy() | Ichki o'zgarishlar asl nusxaga o'tadi | copy.deepcopy() |
[[0] * n] * m | Hamma qator bitta obyekt | [[0] * n for _ in range(m)] |
lst = lst.sort() | None | lst.sort() yoki sorted() |
lst.append([1, 2]) "qo'shish" deb | Ichma-ich ro'yxat | extend |
(5) tuple deb | int | (5,) |
Navbat uchun pop(0) | O(n) — sekin | collections.deque |
Katta ro'yxatda in siklda | O(n²) | set |
max([]) | ValueError | max(lst, default=...) |
| Katta-kichik harfli satrlarni saralash | Katta harflar oldin | key=str.lower |
1. Nusxa topishmoqlari
Kodni bajarmasdan natijani yozing, keyin tekshiring:
import copy
a = [[1], [2]]
b = a
c = a[:]
d = copy.deepcopy(a)
a[0].append(10)
a.append([3])
print(b, c, d, sep="\n")Maslahatni ko'rsatish
Har bir qatorda: yangi tashqi obyekt yaratildimi? Ichki obyektlar umummi? id() bilan tekshiring.
2. Top-k bashoratlar
Model 5 sinf uchun ehtimollar qaytardi:
probs = [0.05, 0.6, 0.1, 0.2, 0.05], classes = ["mushuk", "it", "ot", "sigir", "qo'y"].
Eng yuqori ehtimolli 3 ta sinfni [("it", 0.6), ("sigir", 0.2), ("ot", 0.1)]
ko'rinishida qaytaruvchi top_k(probs, classes, k) funksiyasini yozing.
Maslahatni ko'rsatish
sorted(zip(ehtimollar, sinflar), reverse=True)[:k] yoki sorted(range(len(p)), key=p.__getitem__, reverse=True)[:k].
3. Train/test bo'lish
train_test_split(data, test_ratio=0.2, seed=42) funksiyasini yozing: asl
ro'yxatni o'zgartirmasin, aralashtirsin (random moduli, seed bilan —
natija har safar bir xil bo'lsin), ikki ro'yxat qaytarsin. Hech bir element
ikkala qismga tushmasligini assert bilan tekshiring.
Maslahatni ko'rsatish
random.Random(seed).shuffle(nusxa) — asl ro'yxatni o'zgartirmaslik uchun avval nusxa oling. Bo'lish nuqtasi: int(len * (1 - test_ratio)).
4. Sliding window
windows(seq, size) funksiyasini yozing: ketma-ketlikdan "sirpanuvchi
oyna"lar ro'yxatini qaytarsin: windows([1, 2, 3, 4, 5], 3) →
[[1, 2, 3], [2, 3, 4], [3, 4, 5]]. Bu vaqt qatorlari (time series) va
matnni bo'laklashda (chunking) ishlatiladi. Bonus: step parametrini
qo'shing — windows(seq, 3, step=2) → [[1, 2, 3], [3, 4, 5]].
- 01list — havolalarning dinamik massivi: indeks va append O(1), insert/pop(0)/in — O(n).
- 02b = a — nusxa emas; a.copy() — sayoz nusxa; copy.deepcopy() — to'liq nusxa.
- 03[[0]*n]*m — bitta qatorga m ta havola; list comprehension ishlating.
- 04sorted() yangi ro'yxat, .sort() joyida va None qaytaradi; key= va tuple kalitlar bilan istalgan tartib.
- 05Tuple — o'zgarmas yozuv; bitta elementli tuple uchun vergul shart: (5,).
- 06Unpacking: a, *b = ...; zip(*m) — transpoze va juftlarni ajratish.
- 07Funksiyalar imkon qadar yangi ro'yxat qaytarsin — asl ma'lumotni o'zgartirmasin.
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.
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.
01Top-k bashoratlar
top_k(probs, classes, k) — eng yuqori ehtimolli k ta sinfni [(sinf, ehtimol), ...] ko'rinishida, ehtimol kamayishi tartibida qaytarsin.
02Train/test bo'linishi
train_test_split(data, test_ratio=0.2, seed=42) → (train, test): asl ro'yxat o'zgarmasin, random.Random(seed) bilan aralashtirilsin, test hajmi int(len(data) * test_ratio).
03Sirpanuvchi oyna
windows(seq, size, step=1) — windows([1,2,3,4,5], 3) → [[1,2,3],[2,3,4],[3,4,5]]; windows([1,2,3,4,5], 3, step=2) → [[1,2,3],[3,4,5]]. To'liq bo'lmagan oynalar qo'shilmasin.