IlmHamroh
Python kursi/Satrlar chuqur12/12-dars27 daqiqa
Mundarija (24)

4.12-dars: Immutability — satr nega o'zgarmaydi

4-QISM — SATRLAR CHUQUR · 12-dars · 4-qismning yakuni


1. Kirish va motivatsiya

3.7-darsda o'rgandik: satrlar o'zgarmas. Endi savol — nega?

Bu shunchaki cheklov emas. Bu — Python dizaynidagi asosiy qarorlardan biri va u ko'p narsani belgilaydi:

python
matn = "salom"
matn[0] = "S"                   # ❌ TypeError
python
lugat = {"salom": 1}            # ✅ satr kalit bo'la oladi
lugat = {["a"]: 1}              # ❌ ro'yxat bo'la olmaydi
python
a = "salom"
b = "salom"
print(a is b)                   # True  — bitta obyekt
python
# Va bu — eng amaliy oqibat:
natija = ""
for i in range(100_000):
    natija += str(i)            # ⚠️ har safar YANGI satr

Bu darsda:

  • O'zgarmaslikning to'rt sababi
  • Xeshlanish — nega bu o'zgarmaslikni talab qiladi
  • Internlash — chuqur (4.1-darsning davomi)
  • Satr qurishning barcha usuli va ularning tezligi
  • StringIO, bytearray, array — muqobil vositalar

2. Nazariya — chuqur tushuntirish

2.1. O'zgarmaslik nima

O'zgarmas (immutable) obyekt yaratilgandan keyin o'zgartirilmaydi.

python
matn = "salom"

# matn[0] = "S"                 # ❌ TypeError
# matn.append("!")              # ❌ AttributeError
# del matn[0]                   # ❌ TypeError

matn = "Salom"                  # ✅ lekin bu — YANGI obyekt

Pythondagi o'zgarmas turlar:

text
int  float  complex  bool
str  bytes  tuple  frozenset
range  NoneType

O'zgaruvchan turlar:

text
list  dict  set  bytearray
sinf namunalari (odatda)

Tekshirish — id() bilan (3.1-dars):

python
matn = "salom"
print(id(matn))                 # 140234...

matn = matn.upper()
print(id(matn))                 # 140235...  ← BOSHQA obyekt

royxat = [1, 2]
print(id(royxat))               # 140236...

royxat.append(3)
print(id(royxat))               # 140236...  ← BIR XIL obyekt

Barcha satr metodi yangi satr qaytaradi:

python
matn = "  salom  "

print(id(matn))
print(id(matn.strip()))         # boshqa
print(id(matn.upper()))         # boshqa
print(id(matn.replace("a", "A")))  # boshqa
print(matn)                     # '  salom  ' — o'zgarmadi

Istisno — o'zgarish bo'lmasa:

python
matn = "salom"
print(matn is matn.lower())         # True  — o'zgarish yo'q, o'zini qaytardi
print(matn is matn.replace("z", "x"))   # True — topilmadi
print(matn is matn[:])              # True  — butun kesim
print(matn is matn.upper())         # False — o'zgardi

CPython optimizatsiyasi: o'zgarish bo'lmasa yangi obyekt yaratmaydi. Bu — kafolat emas, amalga oshiruv tafsiloti.

2.2. Nega o'zgarmas — to'rt sabab

1. Xeshlanish — lug'at kaliti bo'la olish

python
lugat = {"salom": 1}            # ✅
tuplam = {"a", "b"}             # ✅

# lugat = {["a"]: 1}            # ❌ TypeError: unhashable type: 'list'

Nega ro'yxat kalit bo'la olmaydi?

python
kalit = [1, 2]
lugat = {kalit: "qiymat"}       # tasavvur qiling, ruxsat berilgan
kalit.append(3)                 # xesh o'zgardi!
lugat[[1, 2, 3]]                # qaysi katakda qidirish kerak?

Xesh jadval element joyini xesh qiymati bo'yicha topadi. Kalit o'zgarsa — element yo'qoladi.

O'zgarmas obyektning xeshi hech qachon o'zgarmaydi:

python
matn = "salom"
print(hash(matn))               # har safar bir xil (shu seansda)

# hash([1, 2])                  # ❌ TypeError
print(hash((1, 2)))             # ✅ juftlik o'zgarmas

2. Xavfsizlik — funksiyaga uzatishda

python
def qayta_ishla(matn: str) -> str:
    return matn.upper()


asl = "salom"
natija = qayta_ishla(asl)
print(asl)                      # 'salom' — KAFOLATLANGAN o'zgarmaydi

Ro'yxat bilan bunday kafolat yo'q:

python
def qayta_ishla(royxat: list) -> list:
    royxat.append("qo'shildi")  # tashqaridagi ro'yxat o'zgardi!
    return royxat


asl = [1, 2]
qayta_ishla(asl)
print(asl)                      # [1, 2, "qo'shildi"] — ⚠️

3. Optimizatsiya — internlash va keshlash

python
a = "salom"
b = "salom"
print(a is b)                   # True — bitta obyekt, xotira tejaldi

Bu faqat o'zgarmas obyektlar uchun xavfsiz.

4. Ko'p oqimli ishlash (thread safety)

O'zgarmas obyektni bir necha oqim qulflashsiz o'qishi mumkin — u o'zgarmaydi.

14-qismda batafsil.

2.3. Xeshlash — chuqur

python
matn = "salom"
print(hash(matn))               # masalan: -8455457274524873561

Xesh har dastur ishga tushganda o'zgaradi:

bash
python -c "print(hash('salom'))"
python -c "print(hash('salom'))"
# Turli natijalar!

Bu — xavfsizlik chorasi (PEP 456). Xesh to'qnashuvi hujumlaridan himoya: hujumchi bir xil xeshli minglab kalit yuborib, lug'atni O(n²) ga tushira olmaydi.

O'chirish (test uchun):

bash
PYTHONHASHSEED=0 python main.py

Sonlar uchun xesh barqaror:

python
print(hash(42))                 # 42
print(hash(42.0))               # 42   — teng qiymat, teng xesh
print(hash(True))               # 1
print(hash(-1))                 # -2   — maxsus holat

Xesh qoidasi:

text
a == b  →  hash(a) == hash(b)     MAJBURIY
hash(a) == hash(b)  ↛  a == b     to'qnashuv mumkin
python
print(42 == 42.0)               # True
print(hash(42) == hash(42.0))   # True — qoida bajarildi

print(1 == True)                # True
print(hash(1) == hash(True))    # True

lugat = {1: "bir", True: "rost", 1.0: "kasr"}
print(lugat)                    # {1: 'kasr'} — hammasi bitta kalit!

O'z sinfingiz uchun (3.11-dars):

python
class Nuqta:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __eq__(self, boshqa):
        return (self.x, self.y) == (boshqa.x, boshqa.y)

    def __hash__(self):
        return hash((self.x, self.y))       # juftlik xeshi

__eq__ yozsangiz __hash__ avtomatik o'chadi:

python
class A:
    def __eq__(self, b): return True

# hash(A())                     # ❌ TypeError: unhashable type

frozen=True bilan dataclass:

python
from dataclasses import dataclass

@dataclass(frozen=True)
class Nuqta:
    x: int
    y: int

n = Nuqta(1, 2)
# n.x = 5                       # ❌ FrozenInstanceError
print(hash(n))                  # ✅ avtomatik __hash__
print({n})                      # ✅ to'plamga qo'shish mumkin

8-qismda batafsil.

2.4. Internlash — chuqur

4.1-darsda tanishgandik. Endi to'liq.

Avtomatik internlash qoidalari (CPython):

python
# 1. Kompilyatsiya paytidagi doimiylar
a = "salom"
b = "salom"
print(a is b)                   # True

# 2. Identifikatorga o'xshash satrlar
a = "foydalanuvchi_ismi"
b = "foydalanuvchi_ismi"
print(a is b)                   # True

# 3. Bo'sh satr va bitta belgi
print("" is "")                 # True
print("a" is "a")               # True

# 4. Doimiylarni birlashtirish
a = "salom"
b = "sal" + "om"                # kompilyator birlashtiradi
print(a is b)                   # True

Internlanmaydiganlar:

python
# Bo'sh joy, tinish belgisi bor
a = "salom dunyo!"
b = "salom dunyo!"
print(a is b)                   # False

# Ishlash paytida yaratilgan
qism = "sal"
c = qism + "om"
print("salom" is c)             # False

# f-satr
ism = "salom"
d = f"{ism}"
print("salom" is d)             # ehtimol False

Qo'lda internlash:

python
import sys

a = sys.intern("salom dunyo!")
b = sys.intern("salom dunyo!")
print(a is b)                   # True

Qachon foydali:

python
# Katta ma'lumotda takrorlanuvchi satrlar
import sys

# ❌ Har biri alohida obyekt
yozuvlar = [{"turi": f"turi_{i % 5}"} for i in range(1_000_000)]

# ✅ Beshta obyekt
TURLAR = [sys.intern(f"turi_{i}") for i in range(5)]
yozuvlar = [{"turi": TURLAR[i % 5]} for i in range(1_000_000)]

Xotira tejaladi va is bilan solishtirish tezlashadi.

Lekin:

python
if matn is "salom":             # ❌ HECH QACHON
if matn == "salom":             # ✅

Internlash — optimizatsiya tafsiloti, kafolat emas. U CPython versiyalari orasida o'zgaradi.

Kichik sonlar keshi (3.1-dars):

python
print(256 is 256)               # True  — keshlangan
print(257 is 257)               # False — (faylda)

Diapazon: -5 dan 256 gacha.

2.5. Satr qurish — barcha usul

Muammo: satrlar o'zgarmas, shuning uchun += har safar yangi satr yaratadi.

python
natija = ""
for i in range(5):
    natija += str(i)
    print(f"  {i}: id={id(natija)}, qiymat={natija!r}")
text
  0: id=140234567890, qiymat='0'
  1: id=140234567920, qiymat='01'
  2: id=140234567950, qiymat='012'
  ...

Har safar boshqa id — yangi obyekt.

Nazariy murakkablik: O(n²) — chunki har safar butun satr nusxalanadi.

Barcha usul:

python
import io
import time

N = 100_000

def usul_qoshish():
    natija = ""
    for i in range(N):
        natija += str(i)
    return natija


def usul_join_generator():
    return "".join(str(i) for i in range(N))


def usul_join_royxat():
    bolaklar = []
    for i in range(N):
        bolaklar.append(str(i))
    return "".join(bolaklar)


def usul_join_comprehension():
    return "".join([str(i) for i in range(N)])


def usul_stringio():
    bufer = io.StringIO()
    for i in range(N):
        bufer.write(str(i))
    return bufer.getvalue()


def usul_map():
    return "".join(map(str, range(N)))


usullar = [
    ("+= bilan", usul_qoshish),
    ("join(generator)", usul_join_generator),
    ("ro'yxat + join", usul_join_royxat),
    ("join(comprehension)", usul_join_comprehension),
    ("StringIO", usul_stringio),
    ("join(map)", usul_map),
]

natijalar = []
for nom, f in usullar:
    boshlandi = time.perf_counter()
    natija = f()
    vaqt = time.perf_counter() - boshlandi
    natijalar.append((nom, vaqt))

eng_tez = min(v for _, v in natijalar)
for nom, vaqt in sorted(natijalar, key=lambda x: x[1]):
    print(f"  {nom:<22} {vaqt * 1000:>8.1f} ms  {vaqt / eng_tez:>5.1f}x")

Tipik natija:

text
  join(map)                18.2 ms    1.0x
  join(comprehension)      21.4 ms    1.2x
  join(generator)          24.8 ms    1.4x
  ro'yxat + join           28.3 ms    1.6x
  StringIO                 31.7 ms    1.7x
  += bilan                 42.1 ms    2.3x

+= kutilganidan tezroq — nega?

CPython'da optimizatsiya bor: agar satrga faqat bitta havola bo'lsa, += uni joyida kengaytirishga urinadi (realloc).

python
natija = ""
natija += "a"           # bitta havola → optimizatsiya ishlaydi

Lekin bu optimizatsiya buziladi:

python
natija = ""
nusxa = natija          # ikkinchi havola!
for i in range(N):
    natija += str(i)    # ❌ optimizatsiya ishlamaydi → O(n²)

Va u kafolatlanmagan:

  • PyPy, Jython, IronPython'da yo'q
  • CPython versiyalari orasida o'zgarishi mumkin
  • Murakkab kodda ishlamasligi mumkin

Qoida:

Katta satr qurishda doim join ishlating. += — faqat bir necha bo'lak uchun.

2.6. io.StringIO — bufer

python
import io

bufer = io.StringIO()
bufer.write("Salom")
bufer.write(", ")
bufer.write("dunyo!")

print(bufer.getvalue())         # 'Salom, dunyo!'
bufer.close()

print bilan:

python
bufer = io.StringIO()
print("Birinchi", file=bufer)
print("Ikkinchi", file=bufer)
print(bufer.getvalue(), end="")

Kontekst menejeri sifatida:

python
with io.StringIO() as bufer:
    bufer.write("matn")
    natija = bufer.getvalue()

Qachon StringIO?

Vaziyat Vosita
Barcha bo'lak oldindan ma'lum join
Bo'laklar shartli qo'shiladi join + ro'yxat
Fayl kabi interfeys kerak (file=) StringIO
print/csv.writer chiqishini ushlash StringIO

Chiqishni ushlash:

python
import contextlib
import io

bufer = io.StringIO()
with contextlib.redirect_stdout(bufer):
    print("Bu buferda")
    print("Bu ham")

print(f"Ushlangan: {bufer.getvalue()!r}")

CSV bilan (4.5-dars):

python
import csv

chiqish = io.StringIO()
yozuvchi = csv.writer(chiqish)
yozuvchi.writerow(["a", "b"])
print(chiqish.getvalue())

2.7. bytearray — o'zgaruvchan baytlar

python
ba = bytearray(b"salom")

ba[0] = 83                      # ✅ o'zgartirish
ba.append(33)                   # ✅ qo'shish
ba.extend(b"!!")                # ✅
print(ba)                       # bytearray(b'Salom!!!')
print(bytes(ba))                # b'Salom!!!'

bytes va bytearray:

bytes bytearray
O'zgaruvchanlik O'zgarmas O'zgaruvchan
Xeshlanadi Ha Yo'q
Literal b"..." Yo'q

Qachon bytearray?

python
# Ikkilik ma'lumotni bosqichma-bosqich qurish
bufer = bytearray()
for bolak in bolaklar:
    bufer.extend(bolak)
malumot = bytes(bufer)

Bu — bytes bilan += dan ancha tez (bytes ham o'zgarmas).

Satr uchun analog yo'q — Pythonda mutable string turi yo'q. Sabab: join yetarlicha tez va sodda.

2.8. Xotira va nusxalash

Kesim yangi obyekt yaratadi (4.2-dars):

python
import sys

katta = "a" * 1_000_000
print(sys.getsizeof(katta))             # ~1,000,049

qism = katta[:500_000]
print(sys.getsizeof(qism))              # ~500,049 — NUSXA

Butun kesim — nusxa emas:

python
print(katta[:] is katta)                # True — satr o'zgarmas

Ro'yxatda esa nusxa:

python
royxat = [1, 2, 3]
print(royxat[:] is royxat)              # False

memoryview — nusxasiz (faqat baytlar uchun):

python
baytlar = b"a" * 1_000_000

nusxa = baytlar[:500_000]               # nusxalaydi
korinish = memoryview(baytlar)[:500_000]  # NUSXALAMAYDI

print(sys.getsizeof(nusxa))             # ~500,033
print(sys.getsizeof(korinish))          # 184 — faqat metama'lumot

Katta faylni qayta ishlashda muhim:

python
# ❌ Butun faylni xotiraga
with open("katta.txt", encoding="utf-8") as f:
    matn = f.read()
    for qator in matn.splitlines():
        ...

# ✅ Qatorma-qator
with open("katta.txt", encoding="utf-8") as f:
    for qator in f:
        ...

16-qismda batafsil.

2.9. sys.getsizeof va haqiqiy xotira

python
import sys

print(sys.getsizeof(""))                # 49
print(sys.getsizeof("a"))               # 50
print(sys.getsizeof("a" * 100))         # 149
print(sys.getsizeof("а"))               # 76 — kirillcha (2 bayt)
print(sys.getsizeof("😊"))              # 80 — 4 bayt

Formula (CPython, ASCII uchun):

text
49 (sarlavha) + uzunlik × 1 bayt

getsizeof ichma-ich obyektlarni hisoblamaydi:

python
royxat = ["a" * 1000 for _ in range(100)]
print(sys.getsizeof(royxat))            # ~920 — faqat ro'yxat!

haqiqiy = sys.getsizeof(royxat) + sum(sys.getsizeof(s) for s in royxat)
print(haqiqiy)                          # ~105,820

To'liq o'lchash:

python
from pympler import asizeof            # pip install pympler
print(asizeof.asizeof(royxat))

Internlash bilan tejash:

python
import sys

N = 100_000

# Har biri alohida obyekt
alohida = [f"turi_{i % 5}" for i in range(N)]
noyob_alohida = len({id(s) for s in alohida})

# Internlangan
internlangan = [sys.intern(f"turi_{i % 5}") for i in range(N)]
noyob_intern = len({id(s) for s in internlangan})

print(f"  Alohida:     {noyob_alohida} noyob obyekt")
print(f"  Internlangan: {noyob_intern} noyob obyekt")

Eslatma: zamonaviy CPython f-satrlarni ham optimallashtiradi, shuning uchun farq ko'rinmasligi mumkin. Bu — amalga oshiruv tafsiloti.


3. Tez ma'lumotnoma

O'zgarmas turlar

text
int  float  complex  bool  str  bytes
tuple  frozenset  range  NoneType

Nega o'zgarmas — 4 sabab

text
1. Xeshlanish  → lug'at kaliti bo'la oladi
2. Xavfsizlik  → funksiyada o'zgartirilmaydi
3. Optimizatsiya → internlash, keshlash
4. Ko'p oqim   → qulflashsiz o'qish

Xesh qoidasi

text
a == b  →  hash(a) == hash(b)     MAJBURIY
__eq__ yozsangiz — __hash__ ham yozing
@dataclass(frozen=True) — avtomatik

Satr qurish

python
"".join(map(str, x))            eng tez
"".join(str(i) for i in x)      generator
"".join([...])                  comprehension
bolaklar.append(); "".join()    shartli qo'shish
io.StringIO()                   fayl interfeysi kerak bo'lsa
natija += x                     ⚠️ faqat bir necha bo'lak

Muqobil vositalar

python
io.StringIO()       matn buferi
bytearray()         o'zgaruvchan baytlar
memoryview()        nusxasiz kesim (baytlar)

Tuzoqlar

python
matn.strip()                natijani SAQLANG
if matn is "salom":         ❌ internlash kafolat emas
sys.getsizeof(royxat)       ichma-ich obyektlarni hisoblamaydi

4. Batafsil misollar

Misol 1 — O'zgarmaslikni ko'rish

python
"""Satrlar o'zgarmas — barcha oqibati."""

import sys

print("=== 1. O'zgartirishga urinish ===")
matn = "salom"

amallar = [
    ("matn[0] = 'S'",        lambda: matn.__setitem__(0, "S")),
    ("matn.append('!')",     lambda: matn.append("!")),
    ("del matn[0]",          lambda: matn.__delitem__(0)),
    ("matn += '!'",          lambda: None),          # ✅ ishlaydi
]

for kod, f in amallar[:3]:
    try:
        f()
        print(f"  {kod:<22} ✅")
    except (TypeError, AttributeError) as x:
        print(f"  {kod:<22} ❌ {type(x).__name__}")


print("\n=== 2. Metodlar yangi obyekt qaytaradi ===")
matn = "  salom  "
print(f"  Asl id: {id(matn)}")

for nom, natija in [("strip()", matn.strip()),
                    ("upper()", matn.upper()),
                    ("replace('a','A')", matn.replace("a", "A"))]:
    print(f"  {nom:<20} id={id(natija)}  {natija!r}")

print(f"  Asl o'zgarmadi: {matn!r}")


print("\n=== 3. Optimizatsiya — o'zgarish bo'lmasa ===")
matn = "salom"
tekshiruvlar = [
    ("matn.lower()",         matn.lower()),
    ("matn.replace('z','x')", matn.replace("z", "x")),
    ("matn[:]",              matn[:]),
    ("matn.upper()",         matn.upper()),
    ("matn.strip()",         matn.strip()),
]

for kod, natija in tekshiruvlar:
    xil = "bir xil obyekt ✅" if natija is matn else "yangi obyekt"
    print(f"  {kod:<24} {xil}")

print("\n  ⚠️ Bu — CPython optimizatsiyasi, KAFOLAT EMAS")


print("\n=== 4. Xeshlanish ===")
obyektlar = [
    ("satr", "salom"),
    ("son", 42),
    ("juftlik", (1, 2)),
    ("frozenset", frozenset([1, 2])),
    ("ro'yxat", [1, 2]),
    ("lug'at", {"a": 1}),
    ("to'plam", {1, 2}),
]

print(f"  {'Tur':<12} {'Xeshlanadi':<12} {'Kalit boʻla oladi'}")
print("  " + "─" * 42)
for nom, obyekt in obyektlar:
    try:
        hash(obyekt)
        print(f"  {nom:<12} {'✅ ha':<12} ✅")
    except TypeError:
        print(f"  {nom:<12} {'❌ yoʻq':<12} ❌")


print("\n=== 5. Nega ro'yxat kalit bo'la olmaydi ===")
print("""
  Tasavvur qiling, ruxsat berilgan:

    kalit = [1, 2]
    lugat = {kalit: "qiymat"}       # xesh(1,2) katakka joylashdi
    kalit.append(3)                 # xesh o'zgardi!
    lugat[kalit]                    # xesh(1,2,3) katakda qidiradi
                                    # → element YO'QOLDI

  O'zgarmas obyektning xeshi hech qachon o'zgarmaydi.
""")


print("=== 6. Funksiyaga uzatish ===")


def satrni_ishla(matn: str) -> str:
    matn = matn.upper()             # mahalliy o'zgaruvchi
    return matn


def royxatni_ishla(royxat: list) -> list:
    royxat.append("qo'shildi")      # TASHQARIDAGI obyekt!
    return royxat


asl_satr = "salom"
satrni_ishla(asl_satr)
print(f"  Satr:    {asl_satr!r}  ← o'zgarmadi ✅")

asl_royxat = [1, 2]
royxatni_ishla(asl_royxat)
print(f"  Ro'yxat: {asl_royxat}  ← O'ZGARDI ⚠️")
text
=== 1. O'zgartirishga urinish ===
  matn[0] = 'S'          ❌ TypeError
  matn.append('!')       ❌ AttributeError
  del matn[0]            ❌ TypeError

=== 3. Optimizatsiya — o'zgarish bo'lmasa ===
  matn.lower()             bir xil obyekt ✅
  matn.replace('z','x')    bir xil obyekt ✅
  matn[:]                  bir xil obyekt ✅
  matn.upper()             yangi obyekt
  matn.strip()             bir xil obyekt ✅

=== 4. Xeshlanish ===
  Tur          Xeshlanadi   Kalit bo'la oladi
  ──────────────────────────────────────────
  satr         ✅ ha         ✅
  son          ✅ ha         ✅
  juftlik      ✅ ha         ✅
  frozenset    ✅ ha         ✅
  ro'yxat      ❌ yo'q       ❌
  lug'at       ❌ yo'q       ❌
  to'plam      ❌ yo'q       ❌

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

Misol 2 — Satr qurish usullari va tezligi

python
"""Barcha usul — o'lchov bilan."""

import io
import sys
import time


def olcha(f, *args) -> tuple[str, float]:
    boshlandi = time.perf_counter()
    natija = f(*args)
    return natija, time.perf_counter() - boshlandi


def usul_qoshish(n):
    natija = ""
    for i in range(n):
        natija += str(i)
    return natija


def usul_qoshish_havola_bilan(n):
    """Ikkinchi havola optimizatsiyani buzadi."""
    natija = ""
    for i in range(n):
        nusxa = natija          # ← ikkinchi havola HAR iteratsiyada
        natija += str(i)        #   (tsikldan oldin bo'lsa, u faqat "" ga
    return natija               #    ishora qilardi va hech narsa buzilmasdi)


def usul_join_map(n):
    return "".join(map(str, range(n)))


def usul_join_generator(n):
    return "".join(str(i) for i in range(n))


def usul_join_comprehension(n):
    return "".join([str(i) for i in range(n)])


def usul_royxat_join(n):
    bolaklar = []
    for i in range(n):
        bolaklar.append(str(i))
    return "".join(bolaklar)


def usul_stringio(n):
    bufer = io.StringIO()
    for i in range(n):
        bufer.write(str(i))
    return bufer.getvalue()


USULLAR = [
    ("join(map)", usul_join_map),
    ("join(comprehension)", usul_join_comprehension),
    ("join(generator)", usul_join_generator),
    ("ro'yxat + join", usul_royxat_join),
    ("StringIO", usul_stringio),
    ("+= bilan", usul_qoshish),
    ("+= (2-havola bilan)", usul_qoshish_havola_bilan),
]

for N in [10_000, 100_000]:
    print(f"\n=== N = {N:,} ===")

    natijalar = []
    kutilgan = None

    for nom, f in USULLAR:
        natija, vaqt = olcha(f, N)
        if kutilgan is None:
            kutilgan = natija
        assert natija == kutilgan, f"{nom} boshqa natija berdi!"
        natijalar.append((nom, vaqt))

    eng_tez = min(v for _, v in natijalar)

    print(f"  {'Usul':<24} {'Vaqt':>10} {'Nisbat':>8}")
    print("  " + "─" * 46)
    for nom, vaqt in sorted(natijalar, key=lambda x: x[1]):
        nisbat = vaqt / eng_tez
        chiziq = "█" * min(int(nisbat * 8), 40)
        print(f"  {nom:<24} {vaqt * 1000:>7.1f} ms {nisbat:>7.1f}x {chiziq}")


print("\n\n=== id() bilan kuzatish ===")
natija = ""
print("  += bilan (bitta havola):")
for i in range(5):
    natija += str(i)
    print(f"    {i}: id={id(natija)}")

print("\n  ⚠️ CPython optimizatsiyasi:")
print("    Agar satrga BITTA havola bo'lsa, += uni joyida")
print("    kengaytirishga urinadi (realloc). Shuning uchun")
print("    id ba'zan o'zgarmaydi.")
print("\n    Lekin bu KAFOLATLANMAGAN:")
print("      • PyPy, Jython'da yo'q")
print("      • Ikkinchi havola bo'lsa ishlamaydi")
print("      • Versiyalar orasida o'zgarishi mumkin")


print("\n\n=== Amaliy tavsiya ===")
print("""
  ✅ Barcha bo'lak ma'lum:
       "".join(map(str, elementlar))

  ✅ Shartli qo'shish:
       bolaklar = []
       for x in elementlar:
           if shart(x):
               bolaklar.append(format(x))
       natija = "".join(bolaklar)

  ✅ Fayl interfeysi kerak (print, csv.writer):
       bufer = io.StringIO()
       print("matn", file=bufer)
       natija = bufer.getvalue()

  ⚠️ Faqat bir necha bo'lak:
       natija = a + b + c
       natija = f"{a}{b}{c}"      ← yaxshiroq
""")

Natijaning muhim qismi:

text
=== N = 100,000 ===
  Usul                           Vaqt   Nisbat
  ──────────────────────────────────────────────
  ...
  += (2-havola bilan)       ... ms    ...x ...

Diqqat: o'sib borayotgan satrga ikkinchi havola bo'lganda += optimizatsiyasi buziladi va har qadamda butun satr nusxalanadi. Farq N bilan kvadratik o'sadi — yuqoridagi o'lchovda 100 000 elementda ~88× (10 000 da esa ~12×) sekinroq.

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

Misol 3 — Internlash va xotira

python
"""Internlash — xotira tejash."""

import sys


def obyektlar_soni(satrlar: list[str]) -> int:
    """Noyob obyektlar sonini qaytaradi."""
    return len({id(s) for s in satrlar})


print("=== 1. Avtomatik internlash ===")
sinovlar = [
    ("salom",              "identifikatorga o'xshash"),
    ("foydalanuvchi_ismi", "pastki chiziq bilan"),
    ("salom dunyo!",       "bo'sh joy va tinish"),
    ("",                   "bo'sh satr"),
    ("x",                  "bitta belgi"),
    ("O'zbekiston",        "apostrof bilan"),
    ("salom123",           "raqam bilan"),
]

print(f"  {'Satr':<22} {'Internlangan':<14} Izoh")
print("  " + "─" * 58)
for matn, izoh in sinovlar:
    a = matn
    b = matn[:]                     # nusxa olishga urinish
    # Kompilyatsiya doimiylarini solishtirish uchun eval
    x = eval(repr(matn))
    y = eval(repr(matn))
    holat = "✅ ha" if x is y else "❌ yo'q"
    print(f"  {matn!r:<22} {holat:<14} {izoh}")


print("\n=== 2. Kompilyatsiya vs ishlash paytida ===")
a = "salom"
b = "sal" + "om"                    # kompilyator birlashtiradi
qism = "sal"
c = qism + "om"                     # ishlash paytida
d = "".join(["sal", "om"])
e = f"sal{'om'}"

print(f"  a = 'salom'              ")
print(f"  b = 'sal' + 'om'         a is b: {a is b}")
print(f"  c = qism + 'om'          a is c: {a is c}")
print(f"  d = ''.join([...])       a is d: {a is d}")
print(f"  e = f'sal{{...}}'          a is e: {a is e}")
print(f"\n  Lekin hammasi teng:      {a == b == c == d == e}")


print("\n=== 3. sys.intern ===")
matn = "salom dunyo!"
a = matn
b = "salom" + " dunyo!"
c = sys.intern(a)
d = sys.intern(b)

print(f"  a is b:  {a is b}")
print(f"  c is d:  {c is d}  ← intern bilan")
print(f"  a is c:  {a is c}")


print("\n=== 4. Xotira tejash ===")
N = 200_000
TURLAR = ["oddiy", "vip", "premium", "sinov", "bloklangan"]

# Har biri alohida obyekt
alohida = []
for i in range(N):
    alohida.append("".join(TURLAR[i % 5]))      # ishlash paytida

# Internlangan
INTERNLANGAN = [sys.intern(t) for t in TURLAR]
internlangan = [INTERNLANGAN[i % 5] for i in range(N)]

print(f"  {N:,} ta element, {len(TURLAR)} xil qiymat\n")
print(f"  Alohida:      {obyektlar_soni(alohida):>8,} noyob obyekt")
print(f"  Internlangan: {obyektlar_soni(internlangan):>8,} noyob obyekt")

# Taxminiy xotira
xotira_alohida = sum(sys.getsizeof(s) for s in set(map(id, alohida)) for s in [""])
print(f"\n  Har bir satr ~{sys.getsizeof('oddiy')} bayt")
print(f"  Alohida:      ~{obyektlar_soni(alohida) * 54:>10,} bayt")
print(f"  Internlangan: ~{obyektlar_soni(internlangan) * 54:>10,} bayt")


print("\n=== 5. Xesh barqarorligi ===")
print(f"  hash('salom') = {hash('salom')}")
print("\n  ⚠️ Bu qiymat HAR DASTUR ISHGA TUSHGANDA o'zgaradi")
print("     Sabab: xesh to'qnashuvi hujumlaridan himoya (PEP 456)")
print("     O'chirish: PYTHONHASHSEED=0")

print(f"\n  Lekin sonlar barqaror:")
for x in [42, 42.0, True, -1, 1000]:
    print(f"    hash({x!r:<6}) = {hash(x)}")


print("\n=== 6. Xesh qoidasi ===")
print(f"  42 == 42.0:              {42 == 42.0}")
print(f"  hash(42) == hash(42.0):  {hash(42) == hash(42.0)}  ← MAJBURIY")
print(f"  1 == True:               {1 == True}")
print(f"  hash(1) == hash(True):   {hash(1) == hash(True)}")

lugat = {1: "bir", True: "rost", 1.0: "kasr"}
print(f"\n  {{1: 'bir', True: 'rost', 1.0: 'kasr'}}")
print(f"  → {lugat}  ← hammasi BITTA kalit!")

Natijaning muhim qismi:

text
=== 2. Kompilyatsiya vs ishlash paytida ===
  a = 'salom'
  b = 'sal' + 'om'         a is b: True
  c = qism + 'om'          a is c: False
  d = ''.join([...])       a is d: False
  e = f'sal{...}'          a is e: False

  Lekin hammasi teng:      True

=== 4. Xotira tejash ===
  200,000 ta element, 5 xil qiymat

  Alohida:       200,000 noyob obyekt
  Internlangan:        5 noyob obyekt

=== 6. Xesh qoidasi ===
  42 == 42.0:              True
  hash(42) == hash(42.0):  True  ← MAJBURIY
  1 == True:               True
  hash(1) == hash(True):   True

  {1: 'bir', True: 'rost', 1.0: 'kasr'}
  → {1: 'kasr'}  ← hammasi BITTA kalit!

Nima ko'rsatdi: 2.3, 2.4, 2.9-bo'limlar.

Misol 4 — Amaliy: HTML generatori

python
"""Satr qurishning to'g'ri usullari — amaliy misol."""

import html
import io
import time
from dataclasses import dataclass


@dataclass
class Mahsulot:
    nom: str
    narx: int
    mavjud: bool
    izoh: str = ""


MAHSULOTLAR = [
    Mahsulot("Klaviatura <Pro>", 250_000, True, "Mexanik, RGB yoritish"),
    Mahsulot("Sichqoncha \"Gaming\"", 120_000, True),
    Mahsulot("Monitor 24\"", 2_500_000, False, "IPS, 1920x1080"),
    Mahsulot("Kabel HDMI & USB", 45_000, True),
]


# ═══ ❌ Yomon usul ═══
def html_qoshish(mahsulotlar: list[Mahsulot]) -> str:
    """+= bilan — sekin va o'qish qiyin."""
    natija = "<table>\n"
    natija += "  <thead><tr><th>Nom</th><th>Narx</th><th>Holat</th></tr></thead>\n"
    natija += "  <tbody>\n"
    for m in mahsulotlar:
        natija += "    <tr>\n"
        natija += f"      <td>{html.escape(m.nom)}</td>\n"
        natija += f"      <td>{m.narx:,}</td>\n"
        natija += f"      <td>{'Bor' if m.mavjud else 'Yoʻq'}</td>\n"
        natija += "    </tr>\n"
    natija += "  </tbody>\n"
    natija += "</table>"
    return natija


# ═══ ✅ join bilan ═══
def html_join(mahsulotlar: list[Mahsulot]) -> str:
    """Ro'yxat + join — tez va toza."""
    qatorlar = [
        "<table>",
        "  <thead><tr><th>Nom</th><th>Narx</th><th>Holat</th></tr></thead>",
        "  <tbody>",
    ]

    for m in mahsulotlar:
        holat = "Bor" if m.mavjud else "Yo'q"
        qatorlar.extend([
            "    <tr>",
            f"      <td>{html.escape(m.nom)}</td>",
            f"      <td>{m.narx:,}</td>",
            f"      <td>{holat}</td>",
            "    </tr>",
        ])

    qatorlar.extend(["  </tbody>", "</table>"])
    return "\n".join(qatorlar)


# ═══ ✅ StringIO bilan ═══
def html_stringio(mahsulotlar: list[Mahsulot]) -> str:
    """StringIO — print bilan qulay."""
    bufer = io.StringIO()

    print("<table>", file=bufer)
    print("  <thead><tr><th>Nom</th><th>Narx</th><th>Holat</th></tr></thead>",
          file=bufer)
    print("  <tbody>", file=bufer)

    for m in mahsulotlar:
        holat = "Bor" if m.mavjud else "Yo'q"
        print("    <tr>", file=bufer)
        print(f"      <td>{html.escape(m.nom)}</td>", file=bufer)
        print(f"      <td>{m.narx:,}</td>", file=bufer)
        print(f"      <td>{holat}</td>", file=bufer)
        print("    </tr>", file=bufer)

    print("  </tbody>", file=bufer)
    print("</table>", file=bufer, end="")

    return bufer.getvalue()


# ═══ ✅ Generator bilan ═══
def html_generator(mahsulotlar: list[Mahsulot]) -> str:
    """Generator — eng ixcham."""
    def qatorlar():
        yield "<table>"
        yield "  <thead><tr><th>Nom</th><th>Narx</th><th>Holat</th></tr></thead>"
        yield "  <tbody>"
        for m in mahsulotlar:
            yield "    <tr>"
            yield f"      <td>{html.escape(m.nom)}</td>"
            yield f"      <td>{m.narx:,}</td>"
            yield f"      <td>{'Bor' if m.mavjud else 'Yo\'q'}</td>"
            yield "    </tr>"
        yield "  </tbody>"
        yield "</table>"

    return "\n".join(qatorlar())


print("=== Natija (join usuli) ===")
print(html_join(MAHSULOTLAR))

print("\n\n=== Barcha usul bir xil natija beradi ===")
natijalar = {
    "qoshish": html_qoshish(MAHSULOTLAR),
    "join": html_join(MAHSULOTLAR),
    "stringio": html_stringio(MAHSULOTLAR),
    "generator": html_generator(MAHSULOTLAR),
}
birinchi = natijalar["join"]
for nom, n in natijalar.items():
    print(f"  {nom:<12} {'✅ bir xil' if n == birinchi else '❌ farqli'}")


print("\n\n=== Tezlik (10 000 mahsulot) ===")
KATTA = MAHSULOTLAR * 2500

usullar = [
    ("+= bilan", html_qoshish),
    ("ro'yxat + join", html_join),
    ("StringIO", html_stringio),
    ("generator + join", html_generator),
]

natijalar = []
for nom, f in usullar:
    boshlandi = time.perf_counter()
    f(KATTA)
    natijalar.append((nom, time.perf_counter() - boshlandi))

eng_tez = min(v for _, v in natijalar)
for nom, vaqt in sorted(natijalar, key=lambda x: x[1]):
    print(f"  {nom:<20} {vaqt * 1000:>7.1f} ms  {vaqt / eng_tez:>5.1f}x")


print("\n\n=== XSS himoyasi ===")
print("  html.escape() ishlatilgani muhim:")
xavfli = Mahsulot("<script>alert('XSS')</script>", 0, True)
print(f"    Xavfli nom: {xavfli.nom}")
print(f"    Ekranlangan: {html.escape(xavfli.nom)}")
text
=== Natija (join usuli) ===
<table>
  <thead><tr><th>Nom</th><th>Narx</th><th>Holat</th></tr></thead>
  <tbody>
    <tr>
      <td>Klaviatura &lt;Pro&gt;</td>
      <td>250,000</td>
      <td>Bor</td>
    </tr>
    ...
  </tbody>
</table>

=== Tezlik (10 000 mahsulot) ===
  ro'yxat + join         28.4 ms    1.0x
  generator + join       31.2 ms    1.1x
  StringIO               42.7 ms    1.5x
  += bilan               58.3 ms    2.1x

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


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

Noto'g'ri fikr To'g'risi
"O'zgarmaslik — cheklov" Xeshlanish, xavfsizlik va optimizatsiyani beradi
"matn.strip() satrni o'zgartiradi" Yangi satr qaytaradi. Natijani saqlang
"+= har doim yangi obyekt yaratadi" CPython optimizatsiyasi bor, lekin kafolatlanmagan
"is satrlar uchun ishonchli" Internlash — amalga oshiruv tafsiloti
"hash('a') doim bir xil" Har dastur ishga tushganda o'zgaradi
"getsizeof to'liq xotirani beradi" Ichma-ich obyektlarni hisoblamaydi
"Pythonda mutable string bor" Yo'q. io.StringIO yoki list + join
"matn[:] nusxa yaratadi" Satrda — yo'q (is matn). Ro'yxatda — ha

6. Keng tarqalgan xatolar va yechimlari

1. Metod natijasini saqlamaslik

python
matn.strip()                        # ❌ natija yo'qoladi
matn = matn.strip()                 # ✅

2. Siklda +=

python
natija = ""
for x in katta:
    natija += str(x)                # ⚠️ sekin

natija = "".join(map(str, katta))   # ✅

3. is bilan solishtirish

python
if matn is "salom":                 # ❌
if matn == "salom":                 # ✅

4. __eq__ bor, __hash__ yo'q

python
class A:
    def __eq__(self, b): ...
# set(a_lar)                        # ❌ TypeError

class A:
    def __eq__(self, b): ...
    def __hash__(self): return hash(...)    # ✅

5. dataclass ni to'plamga qo'shish

python
@dataclass
class A: x: int
# {A(1)}                            # ❌ unhashable

@dataclass(frozen=True)
class A: x: int
print({A(1)})                       # ✅

6. Katta satrni kesish

python
qism = katta[:1000]                 # nusxa yaratadi
# Baytlar uchun:
korinish = memoryview(baytlar)[:1000]   # nusxasiz

7. bytes bilan +=

python
b = b""
for bolak in bolaklar:
    b += bolak                      # ⚠️ bytes ham o'zgarmas

ba = bytearray()                    # ✅
for bolak in bolaklar:
    ba.extend(bolak)
b = bytes(ba)

8. Xesh qiymatini saqlash

python
# ❌ Xesh dastur ishga tushganda o'zgaradi
saqla_bazaga(hash(matn))

import hashlib                      # ✅ barqaror
saqla_bazaga(hashlib.sha256(matn.encode()).hexdigest())

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 3.1-dars (o'tilgan): yorliq modeli, is va ==
  • 3.7-dars (o'tilgan): satr o'zgarmasligi
  • 4.5-dars (o'tilgan): join va tezlik
  • 6-qism: o'zgaruvchan va o'zgarmas to'plamlar, frozenset
  • 6-qism: xeshlash, lug'at ichkarisi
  • 8-qism: __hash__, __eq__, frozen=True
  • 11-qism: xotira boshqaruvi, havolalarni sanash
  • 14-qism: ko'p oqimli ishlash — o'zgarmaslik xavfsizligi

8. Eng yaxshi amaliyotlar

  1. Metod natijasini doim saqlang. matn = matn.strip() — satrlar o'zgarmas.

  2. Katta satr qurishda join. += optimizatsiyasi kafolatlanmagan.

  3. is ni satrlar bilan ishlatmang. Faqat None, True, False.

  4. __eq__ bilan __hash__ yozing. Yoki @dataclass(frozen=True).

  5. Takrorlanuvchi satrlarni internlang. Katta ma'lumotda xotira tejaydi.

  6. Barqaror xesh uchun hashlib. hash() seansdan seansga o'zgaradi.

  7. bytes uchun bytearray ishlating. U ham o'zgarmas.

  8. O'zgarmaslikni afzal ko'ring. O'z sinflaringizda ham — kod xavfsizroq va tushunarliroq bo'ladi.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
matn = "salom"

1.  matn is matn.lower()
2.  matn is matn.upper()
3.  matn is matn[:]
4.  matn is matn.replace("z", "x")
5.  hash("a") == hash("a")
6.  {1: "a", True: "b", 1.0: "c"}
7.  hash((1, 2))
8.  hash([1, 2])
9.  "sal" + "om" is "salom"
10. "".join(["sal", "om"]) is "salom"
Javoblar
  1. False — lower() o'zgarish bo'lmasa ham yangi obyekt qaytaradi (CPython tafsiloti; replace va [:] esa o'zini qaytarishi mumkin)
  2. False
  3. True
  4. True — topilmadi
  5. True — shu seansda
  6. {1: 'c'} — hammasi bitta kalit
  7. Son (masalan -3550055125485641917)
  8. TypeError
  9. True (SyntaxWarning bilan) — kompilyator birlashtiradi
  10. False

Vazifa 2: Tezlikni o'lchash

2-misoldagi barcha usulni o'zingiz yozing va N = 50_000, N = 500_000 uchun o'lchang.

Savol: N oshganda nisbat qanday o'zgaradi? Nega?

Vazifa 3: Xeshlanadigan sinf

Manzil sinfini yarating (shahar, kocha, uy). Talablar:

  1. To'plamga qo'shish mumkin bo'lsin
  2. Lug'at kaliti bo'la olsin
  3. Teng manzillar teng deb hisoblansin (registrsiz)
  4. O'zgartirib bo'lmasin
Yechim
python
from dataclasses import dataclass


@dataclass(frozen=True)
class Manzil:
    shahar: str
    kocha: str
    uy: str

    def __eq__(self, boshqa):
        if not isinstance(boshqa, Manzil):
            return NotImplemented
        return self._kalit() == boshqa._kalit()

    def __hash__(self):
        return hash(self._kalit())

    def _kalit(self):
        return (self.shahar.casefold(),
                self.kocha.casefold(),
                self.uy.casefold())


a = Manzil("Toshkent", "Amir Temur", "12A")
b = Manzil("TOSHKENT", "amir temur", "12a")

print(a == b)               # True
print({a, b})               # bitta element
print(len({a, b}))          # 1

Vazifa 4: Satr quruvchi sinf

SatrQuruvchi sinfini yarating — StringIO ga o'xshash, lekin:

  1. qosh(matn) — bo'lak qo'shadi
  2. qosh_qator(matn) — yangi qator bilan
  3. chekinish(n) — keyingi qatorlar uchun chekinish
  4. natija() — yakuniy satr

Ichkarida ro'yxat + join ishlating.

Vazifa 5: Internlash tajribasi

3-misoldagi tajribani takrorlang, lekin:

  1. 1 000 000 element bilan
  2. Xotirani pympler bilan o'lchang (yoki taxminiy hisoblang)
  3. is bilan solishtirish tezligini ham o'lchang

Vazifa 6: HTML generatorini kengaytirish

4-misoldagi dasturga qo'shing:

  1. CSS sinflari (class="mavjud" / class="yoq")
  2. Ustunlar bo'yicha saralash havolalari
  3. Jami qator
  4. Sahifalash (limit, offset)

Vazifa 7: O'ylash

Nega Pythonda o'zgaruvchan satr turi (mutable string) yo'q, lekin bytearray bor?

Javob

Uch sabab:

1. join yetarlicha tez. Satr qurish uchun "".join(bolaklar) optimallashtirilgan: u avval umumiy uzunlikni hisoblaydi, bir marta xotira ajratadi va nusxalaydi. Bu — o'zgaruvchan satr bilan bir xil murakkablikda (O(n)).

2. Xeshlanish muhimroq. Satrlar eng ko'p ishlatiladigan lug'at kaliti. Agar str o'zgaruvchan bo'lganida, har bir lug'at operatsiyasida nusxa olish kerak bo'lardi — bu butun tilni sekinlashtirardi.

3. bytes uchun holat boshqacha. Ikkilik ma'lumot bilan ishlashda:

  • Bir baytni o'zgartirish tez-tez kerak bo'ladi (protokollar, rasm qayta ishlash)
  • bytes kalit sifatida kam ishlatiladi
  • Bo'lak-bo'lak qurish odatiy holat (tarmoq buferlari)

Shuning uchun bytearray mavjud, lekin u xeshlanmaydi.

Solishtiring boshqa tillar bilan:

Til Satr O'zgaruvchan variant
Python str (o'zgarmas) yo'q (list/StringIO)
Java String (o'zgarmas) StringBuilder
C# string (o'zgarmas) StringBuilder
Go string (o'zgarmas) strings.Builder
Rust String (o'zgaruvchan) —
C++ std::string (o'zgaruvchan) —

Ko'p zamonaviy til satrni o'zgarmas qilgan — bu tasodif emas.

Nimani mustahkamlaydi: 2.1, 2.2, 2.3, 2.4, 2.5-bo'limlar.


Xulosa

Bu darsda o'zgarmaslikni chuqur o'rgandik.

Eng muhim uch fikr:

  1. O'zgarmaslik — cheklov emas, dizayn qarori. U to'rt narsani beradi: xeshlanish (lug'at kaliti bo'la olish), xavfsizlik (funksiyada o'zgartirilmaslik), optimizatsiya (internlash) va ko'p oqimli xavfsizlik.

  2. Katta satr qurishda join. += uchun CPython optimizatsiyasi bor, lekin u kafolatlanmagan — ikkinchi havola paydo bo'lsa yoki boshqa amalga oshiruvda ishlamaydi.

  3. is ni satrlar bilan hech qachon ishlatmang. Internlash — amalga oshiruv tafsiloti: "salom" is "salom" True, lekin "salom dunyo!" is "salom dunyo!" False.


4-QISM YAKUNLANDI

O'n ikki darsni tugatdingiz. Satrlar haqida bilishingiz kerak bo'lgan deyarli hamma narsa endi sizda:

Dars Nima o'rgandingiz
4.1 Ichki tuzilma: PEP 393, kod nuqtasi, grafema, internlash
4.2 Kesimlar: slice obyekti, manfiy qadam, chegara qoidalari
4.3 Qidirish: find/index, isdigit tuzog'i, endswith juftlik
4.4 Tozalash: strip belgilar to'plami, translate, normalizatsiya
4.5 Bo'lish: split ikki rejimi, partition, join
4.6 % va .format(): kechiktirilgan shablon, Template xavfsizligi
4.7 f-satr chuqur: bytecode, {x=}, __format__, PEP 701
4.8 Unicode: normalizatsiya, o'zbek apostroflari, homoglifiya
4.9 Kodlash: UTF-8, mojibake, BOM, "Unicode sendvich"
4.10 Ekranlash: xom satrlar, regex uchun r"", Windows yo'llari
4.11 Ko'p qatorli: textwrap, chekinish, docstring
4.12 O'zgarmaslik: xeshlash, internlash, samarali qurish

Endi siz matn bilan professional darajada ishlay olasiz — foydalanuvchi kiritmasini tozalashdan tortib, Unicode xavfsizligigacha.

Keyingi qism: 5-QISM — BOSHQARUV OQIMI. 12 dars: if/elif/else, sikllar, range, enumerate, zip, break/continue va Python 3.10 dagi match/case. Bu — dasturga mantiq qo'shish qismi.

Bosqich 1 (Poydevor) yakuniga yaqin: 1-4 qismlar tugadi, 5-qism qoldi.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
4.12-dars: Immutability — satr nega o'zgarmaydi — IlmHamroh