Mundarija (22)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. Uch daraja
- 2.2. copy moduli
- 2.3. deepcopy va memo
- 2.4. __copy__ va __deepcopy__
- 2.5. Muqobil usullar
- 2.6. Tezlik va optimallashtirish
- 2.7. Qachon nusxa KERAK EMAS
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — Uch daraja
- Misol 2 — memo va aylanma havolalar
- Misol 3 — __copy__, __deepcopy__ va tezlik
- Misol 4 — Amaliy: undo/redo va holat boshqaruvi
- 5. To'g'ri va noto'g'ri tushunishlar
- 6. Keng tarqalgan xatolar va yechimlari
- 7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 8. Eng yaxshi amaliyotlar
- 9. Amaliy topshiriq
- Xulosa
- 6-QISM YAKUNI
6.18-dars: Nusxa olish — copy va deepcopy
6-QISM — MA'LUMOT TUZILMALARI · 18-dars · 6-QISM YAKUNI
1. Kirish va motivatsiya
6-qismni boshlaganimizda ro'yxat "yorliq" ekanini ko'rdik (6.1-dars):
a = [1, 2, 3]
b = a # nusxa EMAS — bir obyektga ikki yorliq
b.append(4)
print(a) # [1, 2, 3, 4]Yechim — a[:], a.copy(), list(a) edi. Lekin bu yetarli emas:
a = [[1, 2], [3, 4]]
b = a.copy() # "nusxa"
b[0].append(99)
print(a) # [[1, 2, 99], [3, 4]] ⚠️ asl ham o'zgardi!Va yanada nozik holatlar:
import copy
class Sozlamalar:
def __init__(self):
self.teglar = {"a", "b"}
self.ichki = {"x": [1, 2]}
s1 = Sozlamalar()
s2 = copy.copy(s1)
s2.teglar.add("c")
print(s1.teglar) # {'a', 'b', 'c'} ⚠️Va aylanma havolalar:
a = [1, 2]
a.append(a) # o'zini o'z ichiga oladi
copy.deepcopy(a) # ✅ ishlaydi — nega cheksiz rekursiya yo'q?Bu darsda:
- Uch daraja: havola, sayoz nusxa, chuqur nusxa
copy.copyvacopy.deepcopy— qanday ishlaydi- Aylanma havolalar va
memolug'ati __copy__,__deepcopy__— o'z nusxa mantiqingiz- Muqobil usullar va tezlik
- Qachon nusxa kerak emas
2. Nazariya — chuqur tushuntirish
2.1. Uch daraja
a = [[1, 2], [3, 4]]1. Havola (nusxa emas):
b = a
b is a # True
b[0] is a[0] # TrueBitta obyekt, ikki nom. Har qanday o'zgarish ikkalasida ko'rinadi.
2. Sayoz nusxa (shallow copy):
b = a.copy() # yoki a[:], list(a), copy.copy(a)
b is a # False ← yangi ro'yxat
b[0] is a[0] # True ⚠️ ichki obyektlar UMUMIYYangi konteyner, lekin ichidagi obyektlarga havolalar ko'chiriladi.
3. Chuqur nusxa (deep copy):
import copy
b = copy.deepcopy(a)
b is a # False
b[0] is a[0] # False ✅ hammasi yangiVizual:
Havola:
a ──┐
├──→ [ • , • ]
b ──┘ ↓ ↓
[1,2] [3,4]
Sayoz nusxa:
a ──→ [ • , • ]
↓ ↓
[1,2] [3,4]
↑ ↑
b ──→ [ • , • ] ← yangi konteyner, ESKI ichki obyektlar
Chuqur nusxa:
a ──→ [ • , • ] → [1,2] [3,4]
b ──→ [ • , • ] → [1,2] [3,4] ← hammasi yangiSayoz nusxa qachon yetarli:
Ichki obyektlar o'zgarmas bo'lsa:
a = [1, 2, 3] # int — o'zgarmas
b = a.copy()
b[0] = 99
print(a) # [1, 2, 3] ✅ o'zgarmadi
a = ["x", (1, 2), 3.5] # hammasi o'zgarmas
b = a.copy() # ✅ deepcopy kerak emasFaqat bitta o'zgaruvchan element bo'lsa ham — muammo:
a = [1, "x", [2, 3]]
b = a.copy()
b[2].append(4)
print(a) # [1, 'x', [2, 3, 4]] ⚠️2.2. copy moduli
import copy
copy.copy(x) # sayoz
copy.deepcopy(x) # chuqurSayoz nusxa usullari (barchasi teng):
| Tur | Usullar |
|---|---|
list |
a[:], a.copy(), list(a), copy.copy(a) |
dict |
d.copy(), dict(d), {**d}, copy.copy(d) |
set |
s.copy(), set(s), copy.copy(s) |
bytearray |
b[:], bytearray(b), copy.copy(b) |
O'zgarmas turlar uchun nusxa — o'zi:
t = (1, 2)
copy.copy(t) is t # True
copy.deepcopy(t) is t # True ⚠️ (agar ichida o'zgaruvchan yo'q bo'lsa)
s = "abc"
copy.copy(s) is s # True
f = frozenset([1, 2])
f.copy() is f # TrueSabab: o'zgarmas obyektni nusxalash ma'nosiz — hech kim uni o'zgartira olmaydi.
Lekin ichida o'zgaruvchan bo'lsa:
t = (1, [2, 3])
copy.copy(t) is t # True ← sayoz: o'zi qaytadi
copy.deepcopy(t) is t # False ← chuqur: yangi tuplecopy.copy obyektlar uchun:
class A:
def __init__(self):
self.x = 1
self.royxat = [1, 2]
a = A()
b = copy.copy(a)
b is a # False
b.royxat is a.royxat # True ⚠️
b.__dict__ is a.__dict__ # False — yangi lug'atcopy.copy obyekt uchun __dict__ ni sayoz nusxalaydi.
2.3. deepcopy va memo
deepcopy rekursiv ishlaydi va aylanma havolalarni hal qiladi.
a = [1, 2]
a.append(a) # o'zini o'z ichiga oladi
print(a) # [1, 2, [...]]
b = copy.deepcopy(a) # ✅ cheksiz rekursiya YO'Q
b[2] is b # True ← aylanma tuzilma saqlandi
b[2] is a # False ← lekin yangi obyektQanday ishlaydi — memo lug'ati:
def deepcopy(x, memo=None):
if memo is None:
memo = {}
if id(x) in memo:
return memo[id(x)] # ⭐ allaqachon nusxalangan
nusxa = yangi_bosh_konteyner(x)
memo[id(x)] = nusxa # ⭐ REKURSIYADAN OLDIN yozish
for element in x:
nusxa.append(deepcopy(element, memo))
return nusxaIkki muhim jihat:
1. Aylanma havolalar hal qilinadi — memo da allaqachon bo'lsa qaytariladi.
2. Umumiy obyektlar umumiy qoladi:
umumiy = [1, 2]
a = [umumiy, umumiy]
a[0] is a[1] # True
b = copy.deepcopy(a)
b[0] is b[1] # True ⭐ munosabat SAQLANDI
b[0] is a[0] # False ← lekin yangi obyektBu — juda muhim: deepcopy tuzilmaning shaklini saqlaydi.
memo ni qo'lda berish:
memo = {}
b1 = copy.deepcopy(a, memo)
b2 = copy.deepcopy(a, memo)
b1 is b2 # True — memo dan qaytdiNusxalanmaydigan obyektlar:
copy.deepcopy(open("fayl.txt")) # ❌ TypeError
copy.deepcopy(threading.Lock()) # ❌ TypeError
copy.deepcopy(socket.socket()) # ❌ TypeErrorSabab: bu obyektlar OS resurslariga bog'langan — ularni "nusxalash" ma'nosiz.
Atomik turlar nusxalanmaydi (o'zi qaytadi):
copy.deepcopy(42) is 42 # True
copy.deepcopy("abc") is "abc" # True
copy.deepcopy(None) is None # True
copy.deepcopy(int) is int # True ← sinflar ham
copy.deepcopy(print) is print # True ← funksiyalar hamcopy._deepcopy_atomic ro'yxati: type(None), int, float, bool, complex, bytes, str, type, range, types.BuiltinFunctionType, types.FunctionType, weakref.ref, property.
2.4. __copy__ va __deepcopy__
O'z sinfingiz uchun nusxa mantiqini boshqarish:
class Ulanish:
def __init__(self, host, port):
self.host = host
self.port = port
self.soket = self._ulan() # nusxalanmaydigan resurs
self.kesh = {}
def _ulan(self):
return f"<soket {self.host}:{self.port}>"
def __copy__(self):
"""Sayoz nusxa — yangi ulanish, kesh umumiy."""
yangi = Ulanish.__new__(Ulanish)
yangi.__dict__.update(self.__dict__)
yangi.soket = yangi._ulan() # ⭐ yangi resurs
return yangi
def __deepcopy__(self, memo):
"""Chuqur nusxa — hamma narsa yangi."""
yangi = Ulanish.__new__(Ulanish)
memo[id(self)] = yangi # ⭐ REKURSIYADAN OLDIN
yangi.host = self.host
yangi.port = self.port
yangi.soket = yangi._ulan()
yangi.kesh = copy.deepcopy(self.kesh, memo)
return yangi __deepcopy__ da memo[id(self)] = yangi — MAJBURIY va rekursiv chaqiruvlardan oldin bo'lishi kerak. Aks holda aylanma havolada cheksiz rekursiya.
__reduce__ bilan (pickle mexanizmi):
Agar __copy__/__deepcopy__ yo'q bo'lsa, copy moduli __reduce_ex__ ni ishlatadi — bu pickle bilan bir xil mexanizm:
class A:
def __reduce__(self):
return (A, (self.x, self.y)) # (yaratuvchi, argumentlar)Shuning uchun pickle qila oladigan obyekt odatda deepcopy ham qilinadi.
__slots__ bilan:
class B:
__slots__ = ("x", "y")
def __init__(self, x, y):
self.x, self.y = x, ycopy moduli __slots__ ni avtomatik qo'llab-quvvatlaydi (__getstate__/__setstate__ orqali).
2.5. Muqobil usullar
1. JSON roundtrip:
import json
nusxa = json.loads(json.dumps(d))Afzalligi: deepcopy dan ~5-10x tezroq.
Kamchiliklari:
- Faqat JSON turlari:
dict,list,str,int,float,bool,None tuple→listset→ xatodatetime,Decimal→ xato- Lug'at kalitlari satrga aylanadi
- Aylanma havolalar → xato
- Umumiy obyektlar ajraladi (shakl yo'qoladi)
2. pickle roundtrip:
import pickle
nusxa = pickle.loads(pickle.dumps(d))Afzalligi: ko'proq tur, aylanma havolalar ishlaydi, ba'zan deepcopy dan tezroq.
Kamchiliklari: pickle qilinmaydigan obyektlar (lambda, ochiq fayl), xavfsizlik (ishonchsiz ma'lumotni loads qilmang).
3. Qo'lda:
# Ma'lum tuzilma uchun eng tez
nusxa = {k: list(v) for k, v in d.items()}
nusxa = [qator[:] for qator in matritsa]4. O'zgarmas tuzilmalar:
from dataclasses import replace
@dataclass(frozen=True)
class Nuqta:
x: int
y: int
n2 = replace(n1, x=5) # ⭐ nusxa kerak emas — yangi obyektTanlash jadvali:
| Usul | Tezlik | Turlar | Aylanma | Shakl |
|---|---|---|---|---|
copy.copy |
Hammasi | — | — | |
copy.deepcopy |
Hammasi | |||
json |
Cheklangan | |||
pickle |
Ko'p | |||
| Qo'lda | Ma'lum |
2.6. Tezlik va optimallashtirish
deepcopy sekin, chunki:
- Har obyekt uchun tur tekshiruvi
memolug'atiga yozish va o'qish- Rekursiv chaqiruvlar
__reduce_ex__mexanizmi (maxsus turlar uchun)
Taxminiy raqamlar (1000 elementli ichma-ich tuzilma):
copy.copy: ~2 µs
qo'lda nusxa: ~50 µs
json roundtrip: ~400 µs
pickle roundtrip: ~300 µs
copy.deepcopy: ~2000 µsOptimallashtirish:
1. Nusxa kerakmi?
# ❌ Har chaqiruvda nusxa
def qayta_ishla(malumot):
nusxa = copy.deepcopy(malumot)
...
# ✅ O'zgartirmasangiz nusxa kerak emas
def qayta_ishla(malumot):
return [f(x) for x in malumot] # yangi ro'yxat2. Kerakli qismini nusxalang:
copy.deepcopy(katta_obyekt) # ❌
nusxa = {**katta_obyekt, "ozgaradigan": copy.deepcopy(...)} # ✅3. O'zgarmas tuzilmalarga o'ting:
@dataclass(frozen=True) # nusxa umuman kerak emas
class Holat: ...4. __deepcopy__ yozing:
def __deepcopy__(self, memo):
yangi = MeningSinf.__new__(MeningSinf)
memo[id(self)] = yangi
yangi.katta_kesh = self.katta_kesh # ⭐ nusxalamaymiz
yangi.holat = copy.deepcopy(self.holat, memo)
return yangi2.7. Qachon nusxa KERAK EMAS
1. O'zgarmas turlar:
t = (1, 2, 3)
nusxa = t # ✅ nusxa kerak emas2. Yangi obyekt yaratadigan amallar:
yangi = [x * 2 for x in eski] # ✅ eski o'zgarmaydi
yangi = eski + [1] # ✅
yangi = {**d1, **d2} # ✅ (sayoz)
yangi = sorted(eski) # ✅3. Faqat o'qiydigan funksiya:
def yigindi(r):
return sum(r) # ✅ nusxa kerak emas4. Sukut argument (o'zgarmas ishlating):
def f(teglar=()): # ✅ tuple
def f(teglar=frozenset()): # ✅
def f(teglar=None): # ✅
teglar = teglar or []
def f(teglar=[]): # ❌ o'zgaruvchan sukutKlassik xato — funksiya argumentini o'zgartirish:
def qosh_element(r, x):
r.append(x) # ⚠️ CHAQIRUVCHINING ro'yxati o'zgardi
return r
def qosh_element(r, x):
return [*r, x] # ✅ yangi ro'yxatAgar o'zgartirish ataylab bo'lsa, hujjatda yozing va None qaytaring (6.2-dars kelishuvi).
3. Tez ma'lumotnoma
Uch daraja
b = a HAVOLA — bitta obyekt
b = a.copy() SAYOZ — yangi konteyner, ESKI ichki obyektlar
b = copy.deepcopy(a) CHUQUR — hammasi yangiSayoz nusxa usullari
list: a[:], a.copy(), list(a), copy.copy(a)
dict: d.copy(), dict(d), {**d}
set: s.copy(), set(s)
o'zgarmas: copy.copy(t) is t ⚠️ o'zi qaytadideepcopy va memo
memo = {id(obyekt): nusxa}
Aylanma havola: ✅ hal qilinadi
Umumiy obyektlar: ✅ umumiy qoladi (shakl saqlanadi)
Atomik turlar: o'zi qaytadi (int, str, None, funksiya, sinf)
Resurslar: ❌ TypeError (fayl, soket, Lock)Maxsus metodlar
def __copy__(self): ...
def __deepcopy__(self, memo):
yangi = Sinf.__new__(Sinf)
memo[id(self)] = yangi ⭐ REKURSIYADAN OLDIN
...
return yangiMuqobillar
copy.copy ⭐⭐⭐ sayoz
copy.deepcopy ⭐ hamma tur, aylanma, shakl
json roundtrip ⭐⭐ faqat JSON turlari, aylanma ❌
pickle roundtrip ⭐⭐ ko'p tur, aylanma ✅
qo'lda ⭐⭐⭐ ma'lum tuzilma uchunNusxa KERAK EMAS
O'zgarmas turlar t = (1,2)
Yangi obyekt yaratuvchi amallar [x*2 for x in r], {**d1, **d2}
Faqat o'qiydigan funksiya sum(r)
frozen dataclass replace(obj, x=1)4. Batafsil misollar
Misol 1 — Uch daraja
"""Havola, sayoz nusxa, chuqur nusxa — farqlar."""
import copy
print("=== 1. Uch daraja ===")
ASL = [[1, 2], [3, 4], [5, 6]]
havola = ASL
sayoz = ASL.copy()
chuqur = copy.deepcopy(ASL)
print(f" ASL = {ASL}\n")
print(f" {'Usul':<20} {'obyekt is':>11} {'ichki[0] is':>13}")
print(" " + "─" * 48)
print(f" {'b = a':<20} {str(havola is ASL):>11} {str(havola[0] is ASL[0]):>13}")
print(f" {'b = a.copy()':<20} {str(sayoz is ASL):>11} {str(sayoz[0] is ASL[0]):>13}")
print(f" {'b = deepcopy(a)':<20} {str(chuqur is ASL):>11} {str(chuqur[0] is ASL[0]):>13}")
print(f"\n Sinov — b[0].append(99):\n")
for nom, b in [("havola", ASL.copy()), ("sayoz", None), ("chuqur", None)]:
pass
a1 = [[1, 2], [3, 4]]
b1 = a1
b1[0].append(99)
print(f" havola: ASL = {a1} ⚠️")
a2 = [[1, 2], [3, 4]]
b2 = a2.copy()
b2[0].append(99)
print(f" sayoz: ASL = {a2} ⚠️")
a3 = [[1, 2], [3, 4]]
b3 = copy.deepcopy(a3)
b3[0].append(99)
print(f" chuqur: ASL = {a3} ✅")
print(f"\n Sinov — b[0] = 'YANGI' (element ALMASHTIRISH):\n")
a1 = [[1, 2], [3, 4]]
b1 = a1
b1[0] = "YANGI"
print(f" havola: ASL = {a1} ⚠️")
a2 = [[1, 2], [3, 4]]
b2 = a2.copy()
b2[0] = "YANGI"
print(f" sayoz: ASL = {a2} ✅ (konteyner alohida)")
print("""
⭐ Sayoz nusxa KONTEYNERNI ajratadi, ICHKI obyektlarni emas.
• b[0] = x → asl o'zgarmaydi ✅
• b[0].append(x) → asl o'zgaradi ⚠️
""")
print("\n=== 2. Sayoz nusxa qachon yetarli ===")
SINOVLAR = [
("[1, 2, 3]", [1, 2, 3], "int — o'zgarmas"),
("['a', 'b']", ["a", "b"], "str — o'zgarmas"),
("[(1,2), (3,4)]", [(1, 2), (3, 4)], "tuple — o'zgarmas"),
("[1, 'x', 3.5, None]", [1, "x", 3.5, None], "hammasi o'zgarmas"),
("[[1], [2]]", [[1], [2]], "⚠️ list — o'zgaruvchan"),
("[{1}, {2}]", [{1}, {2}], "⚠️ set"),
("[{'a':1}]", [{"a": 1}], "⚠️ dict"),
("[1, [2]]", [1, [2]], "⚠️ bittasi yetarli"),
]
print(f" {'Tuzilma':<24} {'Sayoz yetarlimi':<18} Izoh")
print(" " + "─" * 62)
for nom, asl, izoh in SINOVLAR:
nusxa = copy.copy(asl)
# Ichki obyektlardan biri o'zgaruvchanmi
ozgaruvchan = any(isinstance(x, (list, dict, set, bytearray)) for x in asl)
belgi = "❌ deepcopy kerak" if ozgaruvchan else "✅ ha"
print(f" {nom:<24} {belgi:<18} {izoh}")
print("\n=== 3. Barcha sayoz nusxa usullari ===")
R = [[1, 2], [3, 4]]
D = {"a": [1], "b": [2]}
S = {1, 2, 3}
print(f" Ro'yxat:")
for kod, nusxa in [
("a[:]", R[:]),
("a.copy()", R.copy()),
("list(a)", list(R)),
("copy.copy(a)", copy.copy(R)),
("[*a]", [*R]),
("a + []", R + []),
]:
print(f" {kod:<18} yangi: {nusxa is not R}, "
f"ichki umumiy: {nusxa[0] is R[0]}")
print(f"\n Lug'at:")
for kod, nusxa in [
("d.copy()", D.copy()),
("dict(d)", dict(D)),
("{**d}", {**D}),
("copy.copy(d)", copy.copy(D)),
]:
print(f" {kod:<18} yangi: {nusxa is not D}, "
f"ichki umumiy: {nusxa['a'] is D['a']}")
print(f"\n To'plam:")
for kod, nusxa in [
("s.copy()", S.copy()),
("set(s)", set(S)),
("copy.copy(s)", copy.copy(S)),
("{*s}", {*S}),
]:
print(f" {kod:<18} yangi: {nusxa is not S}")
print("\n=== 4. O'zgarmas turlar ===")
OZGARMASLAR = [
("42", 42),
("'abc'", "abc"),
("(1, 2)", (1, 2)),
("frozenset([1])", frozenset([1])),
("None", None),
("b'bytes'", b"bytes"),
("range(3)", range(3)),
("int", int),
("print", print),
]
print(f" {'Obyekt':<20} {'copy is':>10} {'deepcopy is':>14}")
print(" " + "─" * 48)
for nom, o in OZGARMASLAR:
print(f" {nom:<20} {str(copy.copy(o) is o):>10} "
f"{str(copy.deepcopy(o) is o):>14}")
print(f"\n ⚠️ Ichida o'zgaruvchan bo'lsa:")
t = (1, [2, 3])
print(f" t = (1, [2, 3])")
print(f" copy.copy(t) is t: {copy.copy(t) is t} ← sayoz: o'zi")
print(f" copy.deepcopy(t) is t: {copy.deepcopy(t) is t} ← chuqur: yangi")
d = copy.deepcopy(t)
d[1].append(4)
print(f"\n deepcopy nusxada [1].append(4):")
print(f" t = {t} ✅ o'zgarmadi")
print(f" d = {d}")
print("\n=== 5. Obyektlar ===")
class Sozlamalar:
def __init__(self):
self.nom = "asl"
self.port = 5432
self.teglar = {"a", "b"}
self.ichki = {"x": [1, 2]}
def __repr__(self):
return (f"Sozlamalar(nom={self.nom!r}, port={self.port}, "
f"teglar={sorted(self.teglar)}, ichki={self.ichki})")
s1 = Sozlamalar()
s_sayoz = copy.copy(s1)
s_chuqur = copy.deepcopy(s1)
print(f" s1 = {s1}\n")
print(f" {'':<14} {'obyekt is':>11} {'__dict__ is':>13} {'teglar is':>11}")
print(" " + "─" * 54)
print(f" {'copy.copy':<14} {str(s_sayoz is s1):>11} "
f"{str(s_sayoz.__dict__ is s1.__dict__):>13} "
f"{str(s_sayoz.teglar is s1.teglar):>11}")
print(f" {'copy.deepcopy':<14} {str(s_chuqur is s1):>11} "
f"{str(s_chuqur.__dict__ is s1.__dict__):>13} "
f"{str(s_chuqur.teglar is s1.teglar):>11}")
print(f"\n Sinov:")
s_sayoz.nom = "sayoz"
s_sayoz.teglar.add("c")
s_sayoz.ichki["x"].append(3)
print(f" s_sayoz.nom = 'sayoz' → s1.nom = {s1.nom!r} ✅")
print(f" s_sayoz.teglar.add('c') → s1.teglar = {sorted(s1.teglar)} ⚠️")
print(f" s_sayoz.ichki['x'].append(3) → s1.ichki = {s1.ichki} ⚠️")
s1.teglar.discard("c")
s1.ichki["x"] = [1, 2]
s_chuqur.teglar.add("z")
s_chuqur.ichki["x"].append(9)
print(f"\n s_chuqur.teglar.add('z') → s1.teglar = {sorted(s1.teglar)} ✅")
print(f" s_chuqur.ichki['x'].append(9) → s1.ichki = {s1.ichki} ✅")Natijaning muhim qismi:
=== 1. Uch daraja ===
Usul obyekt is ichki[0] is
────────────────────────────────────────────────
b = a True True
b = a.copy() False True
b = deepcopy(a) False False
Sinov — b[0].append(99):
havola: ASL = [[1, 2, 99], [3, 4]] ⚠️
sayoz: ASL = [[1, 2, 99], [3, 4]] ⚠️
chuqur: ASL = [[1, 2], [3, 4]] ✅
=== 5. Obyektlar ===
obyekt is __dict__ is teglar is
──────────────────────────────────────────────────────
copy.copy False False True
copy.deepcopy False False FalseNima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — memo va aylanma havolalar
"""deepcopy qanday qilib aylanma havolalarni hal qiladi."""
import copy
print("=== 1. Aylanma havola ===")
a = [1, 2]
a.append(a)
print(f" a = [1, 2]; a.append(a)")
print(f" a = {a}")
print(f" a[2] is a: {a[2] is a} ← o'zini o'z ichiga oladi\n")
b = copy.deepcopy(a)
print(f" b = copy.deepcopy(a)")
print(f" b = {b}")
print(f" b[2] is b: {b[2] is b} ✅ aylanma tuzilma SAQLANDI")
print(f" b[2] is a: {b[2] is a} ✅ lekin yangi obyekt")
print(f" b is a: {b is a}")
print(f"\n ⭐ Cheksiz rekursiya YO'Q — memo lug'ati tufayli")
print("\n=== 2. Ikki tomonlama havola ===")
class Tugun:
def __init__(self, nom):
self.nom = nom
self.ota = None
self.bolalar = []
def qosh(self, bola):
bola.ota = self
self.bolalar.append(bola)
return self
def __repr__(self):
return f"Tugun({self.nom!r})"
ildiz = Tugun("ildiz")
a1 = Tugun("a")
b1 = Tugun("b")
ildiz.qosh(a1).qosh(b1)
a1.qosh(Tugun("a1"))
print(f" Daraxt:")
print(f" {ildiz} → {ildiz.bolalar}")
print(f" {a1} → {a1.bolalar}, ota: {a1.ota}")
print(f" ⚠️ Aylanma: ildiz → a → ildiz\n")
nusxa = copy.deepcopy(ildiz)
print(f" Nusxa:")
print(f" nusxa is ildiz: {nusxa is ildiz}")
print(f" nusxa.bolalar[0] is a: {nusxa.bolalar[0] is a1}")
print(f" nusxa.bolalar[0].ota is nusxa: {nusxa.bolalar[0].ota is nusxa} ⭐")
print(f" nusxa.bolalar[0].ota is ildiz: {nusxa.bolalar[0].ota is ildiz}")
print(f"\n ⭐ Ota-bola munosabati TO'G'RI ko'chirildi")
print("\n=== 3. Umumiy obyektlar ===")
UMUMIY = [1, 2, 3]
a = {"birinchi": UMUMIY, "ikkinchi": UMUMIY, "uchinchi": [1, 2, 3]}
print(f" UMUMIY = [1, 2, 3]")
print(f" a = {{'birinchi': UMUMIY, 'ikkinchi': UMUMIY, 'uchinchi': [1,2,3]}}\n")
print(f" a['birinchi'] is a['ikkinchi']: {a['birinchi'] is a['ikkinchi']} ← umumiy")
print(f" a['birinchi'] is a['uchinchi']: {a['birinchi'] is a['uchinchi']} ← alohida")
b = copy.deepcopy(a)
print(f"\n b = copy.deepcopy(a):")
print(f" b['birinchi'] is b['ikkinchi']: {b['birinchi'] is b['ikkinchi']} ⭐ SAQLANDI")
print(f" b['birinchi'] is b['uchinchi']: {b['birinchi'] is b['uchinchi']} ⭐ SAQLANDI")
print(f" b['birinchi'] is a['birinchi']: {b['birinchi'] is a['birinchi']} ← yangi")
b["birinchi"].append(99)
print(f"\n b['birinchi'].append(99):")
print(f" b['birinchi'] = {b['birinchi']}")
print(f" b['ikkinchi'] = {b['ikkinchi']} ⭐ ham o'zgardi (umumiy)")
print(f" b['uchinchi'] = {b['uchinchi']} ← o'zgarmadi")
print(f" a['birinchi'] = {a['birinchi']} ✅ asl butun")
print(f"\n ⚠️ JSON bilan solishtiring:")
import json
c = json.loads(json.dumps(a))
print(f" c = json.loads(json.dumps(a))")
print(f" c['birinchi'] is c['ikkinchi']: {c['birinchi'] is c['ikkinchi']} "
f"⚠️ SHAKL YO'QOLDI")
print("\n=== 4. memo lug'atini kuzatish ===")
class Kuzatuvchi:
"""deepcopy qanday chaqirilishini ko'rsatadi."""
chaqiruvlar = []
def __init__(self, nom):
self.nom = nom
self.havolalar = []
def __deepcopy__(self, memo):
Kuzatuvchi.chaqiruvlar.append(
f"__deepcopy__({self.nom}), memo hajmi: {len(memo)}"
)
yangi = Kuzatuvchi.__new__(Kuzatuvchi)
memo[id(self)] = yangi # ⭐ REKURSIYADAN OLDIN
yangi.nom = self.nom
yangi.havolalar = copy.deepcopy(self.havolalar, memo)
return yangi
def __repr__(self):
return f"K({self.nom})"
a = Kuzatuvchi("a")
b = Kuzatuvchi("b")
c = Kuzatuvchi("c")
a.havolalar = [b, c]
b.havolalar = [a] # aylanma!
c.havolalar = [a, b]
Kuzatuvchi.chaqiruvlar.clear()
nusxa = copy.deepcopy(a)
print(f" Tuzilma: a → [b, c], b → [a], c → [a, b]\n")
print(f" __deepcopy__ chaqiruvlari:")
for i, ch in enumerate(Kuzatuvchi.chaqiruvlar, 1):
print(f" {i}. {ch}")
print(f"\n ⭐ Har obyekt FAQAT BIR MARTA nusxalandi")
print(f" (a, b, c — uchta chaqiruv, aylanma bo'lsa ham)")
print(f"\n Natija tuzilmasi:")
print(f" nusxa.havolalar[0].havolalar[0] is nusxa: "
f"{nusxa.havolalar[0].havolalar[0] is nusxa} ⭐")
print("\n=== 5. memo ni qo'lda berish ===")
ASL = [[1, 2], [3, 4]]
memo = {}
n1 = copy.deepcopy(ASL, memo)
n2 = copy.deepcopy(ASL, memo)
print(f" memo = {{}}")
print(f" n1 = copy.deepcopy(ASL, memo)")
print(f" n2 = copy.deepcopy(ASL, memo)\n")
print(f" n1 is n2: {n1 is n2} ⭐ memo dan qaytdi")
print(f" n1 is ASL: {n1 is ASL}")
print(f" memo hajmi: {len(memo)}")
print(f"\n memo siz:")
n3 = copy.deepcopy(ASL)
n4 = copy.deepcopy(ASL)
print(f" n3 is n4: {n3 is n4} ← alohida nusxalar")
print("""
⭐ memo — bir necha bog'liq obyektni nusxalashda foydali:
bir tuzilmaga havolalar saqlanadi.
""")
print("\n=== 6. ❌ Nusxalanmaydigan obyektlar ===")
import io
import threading
SINOVLAR = [
("io.StringIO()", io.StringIO()),
("threading.Lock()", threading.Lock()),
("(x for x in range(3))", (x for x in range(3))),
("iter([1,2])", iter([1, 2])),
("lambda: 1", lambda: 1),
("print", print),
("int", int),
]
print(f" {'Obyekt':<26} {'copy':<20} {'deepcopy'}")
print(" " + "─" * 62)
for nom, o in SINOVLAR:
try:
copy.copy(o)
c = "✅"
except (TypeError, ValueError) as x:
c = f"❌ {type(x).__name__}"
try:
copy.deepcopy(o)
d = "✅"
except (TypeError, ValueError) as x:
d = f"❌ {type(x).__name__}"
print(f" {nom:<26} {c:<20} {d}")
print("""
⚠️ Resurslar (fayl, soket, Lock) nusxalanmaydi —
ular OS obyektlariga bog'langan.
✅ Yechim: __deepcopy__ da resursni QAYTA YARATING
(yoki umumiy qoldiring, agar xavfsiz bo'lsa).
""")Natijaning muhim qismi:
=== 3. Umumiy obyektlar ===
a['birinchi'] is a['ikkinchi']: True ← umumiy
b = copy.deepcopy(a):
b['birinchi'] is b['ikkinchi']: True ⭐ SAQLANDI
b['birinchi'] is a['birinchi']: False ← yangi
⚠️ JSON bilan solishtiring:
c['birinchi'] is c['ikkinchi']: False ⚠️ SHAKL YO'QOLDI
=== 4. memo lug'atini kuzatish ===
__deepcopy__ chaqiruvlari:
1. __deepcopy__(a), memo hajmi: 0
2. __deepcopy__(b), memo hajmi: 2
3. __deepcopy__(c), memo hajmi: 5
⭐ Har obyekt FAQAT BIR MARTA nusxalandiNima ko'rsatdi: 2.3-bo'lim.
Misol 3 — __copy__, __deepcopy__ va tezlik
"""Nusxa mantiqini boshqarish va optimallashtirish."""
import copy
import time
import json
import pickle
import sys
from dataclasses import dataclass, field, replace
print("=== 1. __copy__ va __deepcopy__ ===")
class Ulanish:
"""Resurs bilan ishlaydigan sinf."""
yaratilgan = 0
def __init__(self, host, port):
self.host = host
self.port = port
self.soket = self._ulan()
self.kesh = {"sorovlar": [], "natijalar": {}}
self.statistika = {"soni": 0}
def _ulan(self):
Ulanish.yaratilgan += 1
return f"<soket#{Ulanish.yaratilgan} {self.host}:{self.port}>"
def __copy__(self):
"""Sayoz — yangi ulanish, kesh UMUMIY."""
yangi = Ulanish.__new__(Ulanish)
yangi.__dict__.update(self.__dict__)
yangi.soket = yangi._ulan() # ⭐ resurs qayta yaratiladi
return yangi
def __deepcopy__(self, memo):
"""Chuqur — hamma narsa yangi."""
yangi = Ulanish.__new__(Ulanish)
memo[id(self)] = yangi # ⭐ REKURSIYADAN OLDIN
yangi.host = self.host
yangi.port = self.port
yangi.soket = yangi._ulan()
yangi.kesh = copy.deepcopy(self.kesh, memo)
yangi.statistika = copy.deepcopy(self.statistika, memo)
return yangi
def __repr__(self):
return f"Ulanish({self.host}:{self.port}, {self.soket})"
u1 = Ulanish("db.wisar.uz", 5432)
u1.kesh["sorovlar"].append("SELECT 1")
print(f" u1 = {u1}")
print(f" u1.kesh = {u1.kesh}\n")
u_sayoz = copy.copy(u1)
u_chuqur = copy.deepcopy(u1)
print(f" {'':<14} {'soket':<32} {'kesh is'}")
print(" " + "─" * 58)
print(f" {'asl':<14} {u1.soket:<32}")
print(f" {'copy':<14} {u_sayoz.soket:<32} {u_sayoz.kesh is u1.kesh}")
print(f" {'deepcopy':<14} {u_chuqur.soket:<32} {u_chuqur.kesh is u1.kesh}")
u_sayoz.kesh["sorovlar"].append("SAYOZ")
u_chuqur.kesh["sorovlar"].append("CHUQUR")
print(f"\n Keshga yozgandan keyin:")
print(f" u1.kesh: {u1.kesh['sorovlar']}")
print(f" u_sayoz.kesh: {u_sayoz.kesh['sorovlar']}")
print(f" u_chuqur.kesh: {u_chuqur.kesh['sorovlar']}")
print("""
⭐ __copy__ / __deepcopy__ — resurslarni to'g'ri boshqarish usuli.
Ularsiz soket "nusxalanardi" (aslida bir xil havola qolardi).
""")
print("\n=== 2. ⚠️ memo ni unutish ===")
class Yomon:
"""❌ memo ga yozmaydi."""
def __init__(self, nom):
self.nom = nom
self.havola = None
def __deepcopy__(self, memo):
yangi = Yomon(self.nom)
# memo[id(self)] = yangi ← YO'Q!
yangi.havola = copy.deepcopy(self.havola, memo)
return yangi
class Yaxshi:
def __init__(self, nom):
self.nom = nom
self.havola = None
def __deepcopy__(self, memo):
yangi = Yaxshi.__new__(Yaxshi)
memo[id(self)] = yangi # ⭐
yangi.nom = self.nom
yangi.havola = copy.deepcopy(self.havola, memo)
return yangi
for sinf, nom in [(Yaxshi, "Yaxshi"), (Yomon, "Yomon")]:
a = sinf("a")
a.havola = a # aylanma
try:
n = copy.deepcopy(a)
natija = f"✅ nusxa.havola is nusxa: {n.havola is n}"
except RecursionError:
natija = "❌ RecursionError"
print(f" {nom:<10} {natija}")
print(f"\n ⭐ memo[id(self)] = yangi — rekursiv chaqiruvlardan OLDIN")
print("\n=== 3. Tezlik solishtirilishi ===")
def katta_tuzilma(n=200):
return {
f"kalit{i}": {
"sonlar": list(range(20)),
"matn": f"qiymat-{i}" * 3,
"ichki": {"a": i, "b": [{"x": j, "y": [j, j + 1]} for j in range(4)]},
}
for i in range(n)
}
KATTA = katta_tuzilma()
USULLAR = []
def olch(nom, f):
boshlandi = time.perf_counter()
natija = f()
return (nom, time.perf_counter() - boshlandi, natija)
USULLAR.append(olch("copy.copy (SAYOZ ⚠️)", lambda: copy.copy(KATTA)))
USULLAR.append(olch("qo'lda (ma'lum tuzilma)", lambda: {
k: {"sonlar": list(v["sonlar"]), "matn": v["matn"],
"ichki": {"a": v["ichki"]["a"],
"b": [{"x": d["x"], "y": list(d["y"])} for d in v["ichki"]["b"]]}}
for k, v in KATTA.items()
}))
USULLAR.append(olch("json roundtrip",
lambda: json.loads(json.dumps(KATTA))))
USULLAR.append(olch("pickle roundtrip",
lambda: pickle.loads(pickle.dumps(KATTA))))
USULLAR.append(olch("copy.deepcopy", lambda: copy.deepcopy(KATTA)))
eng_tez = min(v for _, v, _ in USULLAR)
print(f" {len(KATTA)} ta ichma-ich yozuv:\n")
print(f" {'Usul':<28} {'Vaqt':>10} {'Nisbat':>9} {'Mustaqil'}")
print(" " + "─" * 62)
for nom, vaqt, natija in sorted(USULLAR, key=lambda x: x[1]):
# Mustaqillik tekshiruvi
try:
natija["kalit0"]["sonlar"].append(999)
mustaqil = "✅" if 999 not in KATTA["kalit0"]["sonlar"] else "❌"
if mustaqil == "❌":
KATTA["kalit0"]["sonlar"].remove(999)
except Exception:
mustaqil = "?"
print(f" {nom:<28} {vaqt * 1000:>7.2f} ms {vaqt / eng_tez:>8.1f}x {mustaqil:>9}")
print("\n=== 4. json va pickle cheklovlari ===")
from datetime import datetime
from decimal import Decimal
SINOVLAR = [
("dict/list/str/int", {"a": [1, "x", 2.5, True, None]}),
("tuple", {"a": (1, 2)}),
("set", {"a": {1, 2}}),
("datetime", {"a": datetime(2026, 9, 8)}),
("Decimal", {"a": Decimal("1.5")}),
("bytes", {"a": b"xyz"}),
("int kaliti", {1: "a", 2: "b"}),
]
print(f" {'Ma`lumot':<22} {'json':<24} {'pickle':<12} {'deepcopy'}")
print(" " + "─" * 70)
for nom, malumot in SINOVLAR:
# JSON
try:
j = json.loads(json.dumps(malumot))
j_natija = "✅" if j == malumot else f"⚠️ {type(list(j.values())[0]).__name__}"
except (TypeError, ValueError):
j_natija = "❌ xato"
# pickle
try:
p = pickle.loads(pickle.dumps(malumot))
p_natija = "✅" if p == malumot else "⚠️"
except Exception:
p_natija = "❌"
# deepcopy
try:
d = copy.deepcopy(malumot)
d_natija = "✅" if d == malumot else "⚠️"
except Exception:
d_natija = "❌"
print(f" {nom:<22} {j_natija:<24} {p_natija:<12} {d_natija}")
print(f"\n Aylanma havola bilan:")
a = {"x": 1}
a["o'zi"] = a
for nom, f in [("json", lambda: json.dumps(a)),
("pickle", lambda: pickle.loads(pickle.dumps(a))),
("deepcopy", lambda: copy.deepcopy(a))]:
try:
f()
natija = "✅"
except (ValueError, RecursionError) as x:
natija = f"❌ {type(x).__name__}"
print(f" {nom:<12} {natija}")
print("""
⭐ json: eng cheklangan, lekin tez va o'qiladigan
pickle: ko'p tur, aylanma ✅, lekin xavfsizlik masalasi
deepcopy: hamma narsa, lekin sekin
""")
print("\n=== 5. Optimallashtirish ===")
class KattaObyekt:
"""Katta o'zgarmas kesh + kichik o'zgaruvchan holat."""
def __init__(self):
self.katta_kesh = {i: f"qiymat-{i}" * 10 for i in range(5000)}
self.holat = {"joriy": 0, "tarix": []}
class OptimallashtirilganObyekt(KattaObyekt):
"""__deepcopy__ bilan — kesh nusxalanmaydi."""
def __deepcopy__(self, memo):
yangi = OptimallashtirilganObyekt.__new__(OptimallashtirilganObyekt)
memo[id(self)] = yangi
yangi.katta_kesh = self.katta_kesh # ⭐ UMUMIY (o'zgarmas)
yangi.holat = copy.deepcopy(self.holat, memo)
return yangi
for sinf, nom in [(KattaObyekt, "Sukut deepcopy"),
(OptimallashtirilganObyekt, "__deepcopy__ bilan")]:
o = sinf()
boshlandi = time.perf_counter()
for _ in range(5):
n = copy.deepcopy(o)
vaqt = (time.perf_counter() - boshlandi) / 5
umumiy = n.katta_kesh is o.katta_kesh
print(f" {nom:<24} {vaqt * 1000:>8.2f} ms kesh umumiy: {umumiy}")
print("""
⭐ Katta o'zgarmas ma'lumotni nusxalamaslik —
eng samarali optimallashtirish.
""")
print("\n=== 6. Nusxa KERAK EMAS ===")
@dataclass(frozen=True)
class Holat:
ball: int
daraja: int
teglar: frozenset = frozenset()
h1 = Holat(100, 1, frozenset({"a"}))
h2 = replace(h1, ball=200)
h3 = replace(h1, teglar=h1.teglar | {"b"})
print(f" @dataclass(frozen=True) bilan:\n")
print(f" h1 = {h1}")
print(f" h2 = replace(h1, ball=200)")
print(f" = {h2}")
print(f" h3 = replace(h1, teglar=h1.teglar | {{'b'}})")
print(f" = {h3}")
print(f"\n h1 o'zgarmadi: {h1}")
print(f" ⭐ deepcopy KERAK EMAS — har amal yangi obyekt yaratadi")
print(f"\n Yangi obyekt yaratuvchi amallar:")
AMALLAR = [
("[x*2 for x in r]", "yangi ro'yxat"),
("r + [1]", "yangi ro'yxat"),
("sorted(r)", "yangi ro'yxat"),
("{**d1, **d2}", "yangi lug'at (sayoz)"),
("d1 | d2", "yangi lug'at (sayoz)"),
("s1 | s2", "yangi to'plam"),
("t + (1,)", "yangi tuple"),
("replace(dc, x=1)", "yangi dataclass"),
("nt._replace(x=1)", "yangi namedtuple"),
]
for kod, izoh in AMALLAR:
print(f" {kod:<24} → {izoh}")Natijaning muhim qismi:
=== 3. Tezlik solishtirilishi ===
200 ta ichma-ich yozuv:
Usul Vaqt Nisbat Mustaqil
──────────────────────────────────────────────────────────────
copy.copy (SAYOZ ⚠️) 0.02 ms 1.0x ❌
qo'lda (ma'lum tuzilma) 1.84 ms 92.0x ✅
pickle roundtrip 4.12 ms 206.0x ✅
json roundtrip 6.31 ms 315.5x ✅
copy.deepcopy 28.42 ms 1421.0x ✅
=== 4. json va pickle cheklovlari ===
Ma`lumot json pickle deepcopy
──────────────────────────────────────────────────────────────────────
tuple ⚠️ list ✅ ✅
set ❌ xato ✅ ✅
datetime ❌ xato ✅ ✅
int kaliti ⚠️ str ✅ ✅Nima ko'rsatdi: 2.4, 2.5, 2.6-bo'limlar.
Misol 4 — Amaliy: undo/redo va holat boshqaruvi
"""Nusxa olishning real qo'llanishi."""
import copy
import time
from dataclasses import dataclass, field, replace
from typing import Any
print("=== 1. Undo/Redo — mutable holat bilan ===")
class Hujjat:
"""copy.deepcopy bilan tarix."""
def __init__(self):
self.matn: list[str] = []
self.uslub: dict[str, Any] = {"shrift": "Arial", "hajm": 12}
self.metadata: dict[str, Any] = {"muallif": "", "teglar": []}
self._tarix: list[tuple] = []
self._kelajak: list[tuple] = []
def _holat(self):
return copy.deepcopy((self.matn, self.uslub, self.metadata))
def _tiklash(self, holat):
self.matn, self.uslub, self.metadata = copy.deepcopy(holat)
def _saqlash(self):
self._tarix.append(self._holat())
self._kelajak.clear()
def qator_qosh(self, matn: str):
self._saqlash()
self.matn.append(matn)
return self
def uslub_ozgartir(self, **kwargs):
self._saqlash()
self.uslub.update(kwargs)
return self
def teg_qosh(self, teg: str):
self._saqlash()
self.metadata["teglar"].append(teg)
return self
def bekor(self):
if not self._tarix:
return self
self._kelajak.append(self._holat())
self._tiklash(self._tarix.pop())
return self
def qayta(self):
if not self._kelajak:
return self
self._tarix.append(self._holat())
self._tiklash(self._kelajak.pop())
return self
def __repr__(self):
return (f"Hujjat({len(self.matn)} qator, "
f"{self.uslub}, teglar={self.metadata['teglar']})")
h = Hujjat()
AMALLAR = [
("qator_qosh('Salom')", lambda: h.qator_qosh("Salom")),
("qator_qosh('Dunyo')", lambda: h.qator_qosh("Dunyo")),
("uslub_ozgartir(hajm=14)", lambda: h.uslub_ozgartir(hajm=14)),
("teg_qosh('muhim')", lambda: h.teg_qosh("muhim")),
("bekor()", lambda: h.bekor()),
("bekor()", lambda: h.bekor()),
("qayta()", lambda: h.qayta()),
("qator_qosh('Yangi')", lambda: h.qator_qosh("Yangi")),
("qayta()", lambda: h.qayta()),
]
print(f" {'Amal':<26} {'Holat'}")
print(" " + "─" * 76)
print(f" {'(boshlang`ich)':<26} {h}")
for nom, f in AMALLAR:
f()
print(f" {nom:<26} {h}")
print(f"""
⭐ deepcopy tufayli har holat MUSTAQIL —
tarixdagi holatlar joriy holat bilan bog'lanmagan.
⚠️ Lekin har amal butun holatni nusxalaydi — sekin.
""")
print("\n=== 2. Undo/Redo — o'zgarmas holat bilan ===")
@dataclass(frozen=True)
class HolatIm:
"""O'zgarmas holat — nusxa KERAK EMAS."""
matn: tuple[str, ...] = ()
shrift: str = "Arial"
hajm: int = 12
teglar: frozenset = frozenset()
def qator_qosh(self, matn: str) -> "HolatIm":
return replace(self, matn=(*self.matn, matn))
def uslub_ozgartir(self, **kwargs) -> "HolatIm":
return replace(self, **kwargs)
def teg_qosh(self, teg: str) -> "HolatIm":
return replace(self, teglar=self.teglar | {teg})
def __repr__(self):
return (f"H({len(self.matn)} qator, {self.shrift} {self.hajm}, "
f"teglar={sorted(self.teglar)})")
class HujjatIm:
"""O'zgarmas holat + oddiy ro'yxat = tarix."""
def __init__(self):
self._tarix = [HolatIm()]
self._joy = 0
@property
def holat(self) -> HolatIm:
return self._tarix[self._joy]
def amal(self, f):
yangi = f(self.holat)
self._tarix = self._tarix[:self._joy + 1] + [yangi] # ⭐ nusxa yo'q
self._joy = len(self._tarix) - 1
return self
def bekor(self):
self._joy = max(0, self._joy - 1)
return self
def qayta(self):
self._joy = min(len(self._tarix) - 1, self._joy + 1)
return self
hi = HujjatIm()
AMALLAR2 = [
("qator_qosh('Salom')", lambda h: h.qator_qosh("Salom")),
("qator_qosh('Dunyo')", lambda h: h.qator_qosh("Dunyo")),
("uslub(hajm=14)", lambda h: h.uslub_ozgartir(hajm=14)),
("teg_qosh('muhim')", lambda h: h.teg_qosh("muhim")),
]
print(f" {'Amal':<26} {'Holat'}")
print(" " + "─" * 70)
print(f" {'(boshlang`ich)':<26} {hi.holat}")
for nom, f in AMALLAR2:
hi.amal(f)
print(f" {nom:<26} {hi.holat}")
hi.bekor().bekor()
print(f" {'bekor() ×2':<26} {hi.holat}")
hi.qayta()
print(f" {'qayta()':<26} {hi.holat}")
print(f"\n Tarix uzunligi: {len(hi._tarix)}, joriy: {hi._joy}")
print("""
⭐ O'zgarmas holat bilan:
• deepcopy KERAK EMAS
• Tarix — oddiy ro'yxat
• Umumiy qismlar avtomatik umumiy (structural sharing)
• Ancha tezroq
""")
print("\n=== 3. Tezlik solishtirilishi ===")
N = 300
# Mutable + deepcopy
h1 = Hujjat()
boshlandi = time.perf_counter()
for i in range(N):
h1.qator_qosh(f"Qator {i}")
vaqt_mutable = time.perf_counter() - boshlandi
# Immutable
h2 = HujjatIm()
boshlandi = time.perf_counter()
for i in range(N):
h2.amal(lambda h, i=i: h.qator_qosh(f"Qator {i}"))
vaqt_immutable = time.perf_counter() - boshlandi
print(f" {N} amal + to'liq tarix:\n")
print(f" Mutable + deepcopy: {vaqt_mutable * 1000:>8.1f} ms")
print(f" Immutable: {vaqt_immutable * 1000:>8.1f} ms")
print(f" Farq: {vaqt_mutable / vaqt_immutable:>8.1f}x")
import sys
print(f"\n Xotira (taxminiy):")
print(f" Mutable tarix: {len(h1._tarix)} to'liq nusxa")
print(f" Immutable tarix: {len(h2._tarix)} holat, umumiy qismlar bilan")
print("\n\n=== 4. Sukut argument tuzog'i ===")
def yomon(element, royxat=[]):
"""❌ O'zgaruvchan sukut argument."""
royxat.append(element)
return royxat
def yaxshi(element, royxat=None):
"""✅ None bilan."""
if royxat is None:
royxat = []
royxat.append(element)
return royxat
def yaxshi2(element, royxat=()):
"""✅ O'zgarmas sukut."""
return [*royxat, element]
print(f" ❌ def f(x, royxat=[]):")
print(f" yomon(1) → {yomon(1)}")
print(f" yomon(2) → {yomon(2)} ⚠️ oldingi qiymat qoldi!")
print(f" yomon(3) → {yomon(3)} ⚠️")
print(f"\n ✅ def f(x, royxat=None):")
print(f" yaxshi(1) → {yaxshi(1)}")
print(f" yaxshi(2) → {yaxshi(2)}")
print(f" yaxshi(3) → {yaxshi(3)}")
print(f"\n ✅ def f(x, royxat=()):")
print(f" yaxshi2(1) → {yaxshi2(1)}")
print(f" yaxshi2(2) → {yaxshi2(2)}")
print(f"\n Sabab:")
print(f" yomon.__defaults__ = {yomon.__defaults__}")
print(f" ⚠️ Sukut qiymat FUNKSIYA YARATILGANDA bir marta hisoblanadi")
print("\n\n=== 5. Funksiya argumentini o'zgartirish ===")
def yomon_qosh(royxat, element):
"""⚠️ Chaqiruvchining ro'yxatini o'zgartiradi."""
royxat.append(element)
return royxat
def yaxshi_qosh(royxat, element):
"""✅ Yangi ro'yxat qaytaradi."""
return [*royxat, element]
def aniq_qosh(royxat, element) -> None:
"""✅ Ataylab joyida — None qaytaradi (6.2-dars kelishuvi)."""
royxat.append(element)
ASL = [1, 2, 3]
r1 = ASL.copy()
natija = yomon_qosh(r1, 4)
print(f" yomon_qosh(r, 4):")
print(f" natija = {natija}")
print(f" r = {r1} ⚠️ o'zgardi")
print(f" natija is r: {natija is r1}")
r2 = ASL.copy()
natija = yaxshi_qosh(r2, 4)
print(f"\n yaxshi_qosh(r, 4):")
print(f" natija = {natija}")
print(f" r = {r2} ✅ o'zgarmadi")
r3 = ASL.copy()
natija = aniq_qosh(r3, 4)
print(f"\n aniq_qosh(r, 4):")
print(f" natija = {natija} ⭐ None — 'joyida o'zgartirdim' signali")
print(f" r = {r3}")
print("""
⭐ Uch variant:
1. Yangi obyekt qaytaring — eng xavfsiz
2. Joyida o'zgartiring va None qaytaring — aniq signal
3. ❌ Joyida o'zgartirib, obyektni qaytarish — chalkash
""")
print("\n=== 6. 6-QISM YAKUNI: qaysi tuzilma qachon ===")
print("""
┌──────────────────────────┬────────────────────────────────────┐
│ Vazifa │ Tuzilma │
├──────────────────────────┼────────────────────────────────────┤
│ Tartibli ketma-ketlik │ list │
│ O'zgarmas yozuv │ tuple / NamedTuple │
│ Nomli maydonlar │ NamedTuple / dataclass │
│ Noyoblik + tez `in` │ set │
│ O'zgarmas to'plam, kalit │ frozenset │
│ Kalit → qiymat │ dict │
│ Sanash │ Counter │
│ Guruhlash │ defaultdict(list) │
│ Qatlamlar │ ChainMap │
│ LRU / FIFO │ OrderedDict / deque │
│ Navbat │ deque │
│ Bir turdagi sonlar │ array / numpy │
│ Bir marta o'tish │ generator ifodasi │
│ O'zgarmas holat │ frozen dataclass + replace() │
└──────────────────────────┴────────────────────────────────────┘
Nusxa olish:
O'zgarmas turlar → nusxa kerak emas
Ichida faqat o'zgarmas → a.copy() yetarli
Ichma-ich o'zgaruvchan → copy.deepcopy()
Katta + JSON turlari → json roundtrip (tezroq)
Resurslar bor → __deepcopy__ yozing
Tez-tez nusxa kerak → o'zgarmas tuzilmalarga o'ting
""")Natijaning muhim qismi:
=== 1. Undo/Redo — mutable holat bilan ===
Amal Holat
────────────────────────────────────────────────────────────────────────────
(boshlang`ich) Hujjat(0 qator, {'shrift': 'Arial', 'hajm': 12}, teglar=[])
qator_qosh('Salom') Hujjat(1 qator, {'shrift': 'Arial', 'hajm': 12}, teglar=[])
uslub_ozgartir(hajm=14) Hujjat(2 qator, {'shrift': 'Arial', 'hajm': 14}, teglar=[])
bekor() Hujjat(2 qator, {'shrift': 'Arial', 'hajm': 14}, teglar=[])
=== 3. Tezlik solishtirilishi ===
300 amal + to'liq tarix:
Mutable + deepcopy: 184.2 ms
Immutable: 4.1 ms
Farq: 44.9x
=== 4. Sukut argument tuzog'i ===
❌ def f(x, royxat=[]):
yomon(1) → [1]
yomon(2) → [1, 2] ⚠️ oldingi qiymat qoldi!Nima ko'rsatdi: 2.5, 2.6, 2.7-bo'limlar.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"a.copy() to'liq nusxa" |
Sayoz — ichki obyektlar umumiy |
"deepcopy aylanma havolada osilib qoladi" |
memo bilan hal qilinadi |
"deepcopy umumiy obyektlarni ajratadi" |
Shakl saqlanadi |
"json roundtrip deepcopy o'rnini bosadi" |
Turlar cheklangan, shakl yo'qoladi |
"copy.copy(t) is t xato" |
O'zgarmas tur uchun to'g'ri |
"__deepcopy__ da memo ixtiyoriy" |
Majburiy — aylanmada rekursiya |
| "Har o'zgartirishdan oldin nusxa kerak" | Ko'p amal allaqachon yangi obyekt beradi |
"deepcopy har doim ishlaydi" |
Fayl, soket, Lock — TypeError |
| "Funksiya argumentini o'zgartirish normal" | Chaqiruvchini ajablantiradi |
6. Keng tarqalgan xatolar va yechimlari
1. Sayoz nusxaga ishonish
n = d.copy()
n["ichki"]["x"] = 1 # ⚠️ asl ham o'zgardi
n = copy.deepcopy(d) # ✅2. __deepcopy__ da memo ni unutish
def __deepcopy__(self, memo):
yangi = Sinf()
yangi.h = copy.deepcopy(self.h, memo) # ❌ aylanmada RecursionError
return yangi
def __deepcopy__(self, memo):
yangi = Sinf.__new__(Sinf)
memo[id(self)] = yangi # ✅
yangi.h = copy.deepcopy(self.h, memo)
return yangi3. O'zgaruvchan sukut argument
def f(r=[]): # ❌
def f(r=None): # ✅
r = [] if r is None else r
def f(r=()): # ✅4. json bilan noto'g'ri turlar
json.loads(json.dumps(d)) # ⚠️ set, datetime, tuple
copy.deepcopy(d) # ✅5. Keraksiz deepcopy
def f(malumot):
n = copy.deepcopy(malumot) # ⚠️ o'zgartirmasangiz kerak emas
return sum(n)
def f(malumot):
return sum(malumot) # ✅6. Funksiya argumentini o'zgartirish
def qosh(r, x):
r.append(x); return r # ⚠️ chaqiruvchi ajablanadi
def qosh(r, x):
return [*r, x] # ✅7. Sinf atributi sifatida o'zgaruvchan
class A:
teglar = [] # ⚠️ BARCHA obyektlarga umumiy
class A:
def __init__(self):
self.teglar = [] # ✅8. Katta obyektni to'liq nusxalash
copy.deepcopy(katta_obyekt) # ⚠️ sekin
def __deepcopy__(self, memo): # ✅
yangi.katta_kesh = self.katta_kesh # o'zgarmas — umumiy7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 6.1-dars (o'tilgan): yorliq modeli — bu darsning asosi
- 6.14-dars (o'tilgan): ichma-ich tuzilmalar
- 6.5, 6.9-darslar (o'tilgan): o'zgarmaslik va hashlanish
- 7-qism: sukut argumentlar, funksiya argumentlarini o'zgartirish
- 8-qism:
__copy__,__deepcopy__,dataclass(frozen=True) - 16-qism:
pickle, serializatsiya - 11, 18-qismlar: profillash, GC, xotira
8. Eng yaxshi amaliyotlar
Ichma-ich tuzilma uchun
deepcopy.copy()deyarli har doim yetarli emas.Nusxa kerakmi — o'ylab ko'ring. Ko'p amal allaqachon yangi obyekt beradi.
O'zgarmas tuzilmalarga o'ting.
frozen dataclass+replace()— nusxa umuman kerak emas.__deepcopy__damemo[id(self)]ni birinchi qatorda. Rekursiv chaqiruvlardan oldin.Resurslar uchun
__copy__/__deepcopy__yozing. Soket, fayl, ulanish.Sukut argument — o'zgarmas yoki
None.[],{},set()— hech qachon.Funksiya argumentini o'zgartirmang. Yoki
Noneqaytaring.Tezlik muhim bo'lsa qo'lda nusxalang. Tuzilma ma'lum bo'lsa
deepcopydan 10-50x tez.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
import copy
a = [[1, 2], [3, 4]] # ⚠️ har band ALOHIDA: a har safar shu qiymatdan boshlanadi
1. b = a; b[0].append(9); print(a)
2. b = a.copy(); b[0].append(9); print(a)
3. b = copy.deepcopy(a); b[0].append(9); print(a)
4. b = a.copy(); b[0] = "X"; print(a)
5. t = (1, [2]); print(copy.copy(t) is t)
6. t = (1, [2]); print(copy.deepcopy(t) is t)
7. print(copy.deepcopy(42) is 42)
8. print(copy.deepcopy(print) is print)
9. u = [1]; a2 = [u, u]; b2 = copy.deepcopy(a2); print(b2[0] is b2[1])
10. import json; a3 = {"x": [1], "y": [1]}
a3["y"] = a3["x"]; c = json.loads(json.dumps(a3)); print(c["x"] is c["y"])
11. x = [1]; x.append(x); print(len(copy.deepcopy(x)))
12. print(copy.copy(frozenset([1])) is copy.copy(frozenset([1])))Javoblar
[[1, 2, 9], [3, 4]]— havola[[1, 2, 9], [3, 4]]— sayoz[[1, 2], [3, 4]]— chuqur[[1, 2], [3, 4]]— konteyner alohidaTrue— sayoz: o'zi qaytadiFalse— chuqur: ichida list borTrue— atomikTrue— funksiya atomikTrue— shakl saqlandiFalse— JSON shaklni yo'qotadi2—[1, [...]]False— turlifrozensetobyektlari (interning yo'q)
Vazifa 2: Xatolarni tuzating
1. n = konfiguratsiya.copy(); n["baza"]["host"] = "yangi"
2. def f(x, r=[]): r.append(x); return r
3. def __deepcopy__(self, memo):
y = Sinf(); y.h = copy.deepcopy(self.h, memo); return y
4. n = json.loads(json.dumps(d)) # d da datetime va set bor
5. def qosh(r, x): r.append(x); return r
6. class A: teglar = []
7. def f(m): n = copy.deepcopy(m); return sum(n)
8. copy.deepcopy(obyekt) # obyektda ochiq fayl borJavoblar
1. n = copy.deepcopy(konfiguratsiya)
2. def f(x, r=None): r = [] if r is None else r; r.append(x); return r
3. y = Sinf.__new__(Sinf); memo[id(self)] = y; y.h = ...
4. n = copy.deepcopy(d)
5. def qosh(r, x): return [*r, x]
6. class A:
def __init__(self): self.teglar = []
7. def f(m): return sum(m)
8. __deepcopy__ yozing — faylni qayta oching yoki tashlab yuboringVazifa 3: Nusxa tahlilchisi
Funksiya yozing:
def nusxa_tahlil(obyekt) -> dict:
"""Sayoz nusxa yetarlimi, deepcopy kerakmi, nusxalanadimi."""- O'zgaruvchan ichki obyektlarni topsin
- Aylanma havolalarni aniqlasin
- Nusxalanmaydigan obyektlarni topsin
- Taxminiy
deepcopyvaqtini baholasin - Tavsiya bersin (
copy,deepcopy,json, qo'lda)
Vazifa 4: Tez nusxa generatori
Ma'lum sxema uchun optimal nusxa funksiyasini generatsiya qiluvchi vosita:
- Namunadan tuzilmani aniqlash
- Qo'lda nusxa kodini yaratish (
execbilan) - O'zgarmas qismlarni nusxalamaslik
deepcopybilan tezlikni solishtirish- To'g'riligini tekshirish (tasodifiy ma'lumot bilan)
Vazifa 5: Undo/Redo tizimi
Ikki versiyani yozing va solishtiring:
- Mutable +
deepcopy - Immutable +
replace - Command pattern (faqat o'zgarishlarni saqlash)
- Har biri uchun: tezlik, xotira, kod murakkabligi
- Tarix chegarasi (
maxlen) - Guruhlangan amallar (bir necha o'zgarishni bitta undo bilan)
Vazifa 6: Resurs boshqaruvi
__copy__ va __deepcopy__ bilan sinflar:
Ulanish— soketni qayta yaratadiKattaKesh— keshni umumiy qoldiradiHujjat— faylni qayta ochadiSozlamalar— faqat o'zgargan maydonlarni nusxalaydi- Har biri uchun testlar (aylanma havola bilan ham)
Vazifa 7: O'ylash
Nega copy.deepcopy shunchalik sekin, va nega buni tezlashtirish qiyin?
Javob
Sabab: u umumiy, xavfsiz va to'g'ri bo'lishi kerak.
Har obyekt uchun deepcopy nima qiladi:
def deepcopy(x, memo):
# 1. memo tekshiruvi — aylanma va umumiy obyektlar uchun
y = memo.get(id(x), _nil)
if y is not _nil:
return y
# 2. Tur bo'yicha dispatcher
cls = type(x)
copier = _deepcopy_dispatch.get(cls)
if copier is not None:
y = copier(x, memo)
else:
# 3. __deepcopy__ bormi
copier = getattr(x, "__deepcopy__", None)
if copier is not None:
y = copier(memo)
else:
# 4. __reduce_ex__ (pickle protokoli)
rv = x.__reduce_ex__(4)
y = _reconstruct(x, memo, *rv)
# 5. memo ga yozish
if y is not x:
memo[id(x)] = y
_keep_alive(x, memo) # ⚠️ GC dan himoya
return yHar qadamning narxi:
| Qadam | Narx |
|---|---|
memo.get(id(x)) |
Hash hisoblash + lug'at qidiruvi |
type(x) + dispatch |
Lug'at qidiruvi |
getattr(x, "__deepcopy__") |
Atribut qidiruvi (MRO bo'ylab) |
__reduce_ex__ |
Funksiya chaqiruvi + tuple yaratish |
memo[id(x)] = y |
Lug'at yozuvi |
_keep_alive |
Yana lug'at amali |
Bu — har bir element uchun. 10 000 elementli tuzilmada 60 000+ lug'at amali.
Nega tezlashtirib bo'lmaydi:
1. memo — majburiy.
Aylanma havolalar va umumiy obyektlar uchun id → nusxa xaritasi kerak. Uni olib tashlash deepcopy ni noto'g'ri qiladi.
2. Tur oldindan noma'lum.
deepcopy har qanday obyekt bilan ishlashi kerak: ichki turlar, foydalanuvchi sinflari, C kengaytmalari, __slots__ li sinflar, meros bilan... Har biri uchun dispatch kerak.
Qo'lda nusxada esa tur ma'lum:
nusxa = {k: list(v) for k, v in d.items()} # dispatch yo'q3. _keep_alive — GC muammosi.
def _keep_alive(x, memo):
try:
memo[id(memo)].append(x)
except KeyError:
memo[id(memo)] = [x]memo id() bilan ishlaydi. Agar asl obyekt GC tomonidan yig'ilsa, uning id si qayta ishlatilishi mumkin — va memo da noto'g'ri moslik paydo bo'ladi.
Shuning uchun deepcopy barcha asl obyektlarga havolani saqlaydi. Bu — qo'shimcha xotira va vaqt, lekin to'g'rilik uchun majburiy.
4. __reduce_ex__ — umumiy, lekin sekin.
Maxsus metodsiz sinflar uchun deepcopy pickle protokolini ishlatadi:
rv = x.__reduce_ex__(4) # (yaratuvchi, args, holat, ...)
y = _reconstruct(x, memo, *rv)Bu — bir necha funksiya chaqiruvi va tuple yaratish har obyekt uchun.
Nima tezroq bo'lishi mumkin:
C da amalga oshirish. deepcopy — sof Python. C versiyasi 3-5x tezroq bo'lardi.
Bu bir necha marta taklif qilingan (bpo-issue'lar bor), lekin qabul qilinmagan:
- Murakkab logika (pickle protokoli,
__reduce_ex__) - Foydalanuvchi kodini chaqirish (
__deepcopy__) — C dan qiyin - Talab past: ko'p kod
deepcopyni tor joyda ishlatmaydi
Amaliy yechimlar:
# 1. Nusxa kerakmi?
# 2. O'zgarmas tuzilmalar (nusxa umuman kerak emas)
# 3. Qo'lda nusxa (tuzilma ma'lum)
# 4. __deepcopy__ (katta o'zgarmas qismlarni o'tkazib yuborish)
# 5. pickle (ba'zan tezroq)
# 6. Tashqi kutubxona: `msgspec`, `orjson` (JSON turlari uchun)Xulosa: deepcopy sekin, chunki u hech qanday taxmin qilmaydi. U har qanday obyekt bilan, har qanday tuzilmada, aylanma havolalar va umumiy obyektlar bilan to'g'ri ishlaydi. Bu universallik narxi.
Sizning kodingiz esa tuzilmani biladi — shuning uchun qo'lda nusxa har doim tezroq bo'ladi. Va eng yaxshi yechim — nusxa umuman kerak bo'lmaydigan dizayn.
Nimani mustahkamlaydi: 2.3, 2.5, 2.6, 2.7-bo'limlar.
Xulosa
Bu darsda nusxa olishni o'rgandik — va 6-qismni yakunladik.
Eng muhim uch fikr:
Uch daraja bor: havola, sayoz, chuqur.
b = a— bitta obyekt,a.copy()— yangi konteyner lekin eski ichki obyektlar,deepcopy(a)— hammasi yangi. Ichma-ich tuzilma uchun deyarli har doimdeepcopykerak.memo—deepcopyning yuragi. U aylanma havolalarni hal qiladi va umumiy obyektlarni umumiy qoldiradi (tuzilma shaklini saqlaydi).jsonroundtrip tezroq, lekin shaklni yo'qotadi va turlari cheklangan.Eng yaxshi nusxa — kerak bo'lmagan nusxa.
frozen dataclass+replace(), generator ifodalari, yangi obyekt qaytaruvchi amallar — bularning hech biri nusxa talab qilmaydi va ancha tezroq.
6-QISM YAKUNI
Bu qismda Pythonning barcha asosiy ma'lumot tuzilmalarini o'rgandik:
| Dars | Mavzu | Asosiy fikr |
|---|---|---|
| 1-4 | list |
Yorliq modeli, metodlar, saralash, xotira |
| 5-6 | tuple |
O'zgarmaslik, hashlanish, nomli maydonlar |
| 7-9 | set |
O(1) in, to'plam amallari, frozenset |
| 10-13 | dict |
Tartib kafolati, collections, hash |
| 14 | Ichma-ich | Xavfsiz o'qish, rekursiya |
| 15-17 | Generatorlar | Sintaksis, dangasa hisoblash |
| 18 | Nusxa | Uch daraja, memo |
Uch umumiy tamoyil:
O'zgaruvchanlik — asosiy ajratuvchi.
list/dict/seto'zgaruvchan (hashlanmaydi),tuple/frozenset/stro'zgarmas (hashlanadi, kalit bo'la oladi).Hash jadvali — tezlikning asosi.
setvadictinni O(n) dan O(1) ga tushiradi, evaziga ~4x xotira oladi. Bu — deyarli har doim foydali savdo.To'g'ri tuzilmani tanlash — eng katta optimallashtirish.
listo'rnigaset(tekshiruv uchun),Counter(sanash),defaultdict(guruhlash),deque(navbat), generator (oqim) — har biri O(n²) ni O(n) ga aylantiradi.
Keyingi qism — 7-qism: Funksiyalar. U yerda argumentlar, qamrov, lambda, rekursiya va tur ko'rsatkichlarini chuqur o'rganamiz.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!