Mundarija (21)
- 1. Kirish va motivatsiya
- 2. Nazariya — chuqur tushuntirish
- 2.1. is — identifikatsiya
- 2.2. == protokoli
- 2.3. Konteynerlar is ni avval tekshiradi
- 2.4. Teng, lekin turli qiymatlar
- 2.5. NaN — o'ziga teng bo'lmagan qiymat
- 2.6. is qachon to'g'ri
- 2.7. Belgi obyekti (sentinel) naqshi
- 3. Tez ma'lumotnoma
- 4. Batafsil misollar
- Misol 1 — == protokolini kuzatish
- Misol 2 — Konteynerlarda identifikatsiya qisqa yo'li
- Misol 3 — Teng qiymatlar va xesh
- Misol 4 — Amaliy: is to'g'ri va noto'g'ri ishlatilganda
- 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
11.2-dars: id, is va ==
11-QISM — OBYEKT MODELI VA XOTIRA · 2-dars
1. Kirish va motivatsiya
3.11-darsda is va == farqini qisqacha ko'rgan edik: is — "bir xil obyektmi", == — "qiymati tengmi". Amalda bu farq kutilmagan joylarda chiqadi.
1-hodisa. Testlar o'tadi, ishlab chiqarishda esa emas:
def holat_kodi(javob):
kod = javob.status
if kod is 200: # testda kod = 200 (literal) → True
return "ok"
return "xato" # ishlab chiqarishda kod = int("200") → har doim "xato"?Aslida 200 kichik son va o'lmas bo'lgani uchun bu kod ishlab chiqarishda ham ishlaydi. Kimdir limitni 1000 ga o'zgartirgach — yo'q.
2-hodisa. Ma'lumotlarni tozalash skripti takrorlanuvchi o'lchovlarni olib tashlaydi:
noyob = set(olchovlar) # [nan, nan, nan, 12.5, ...]Natijada uchta nan qoladi — ular bir-biriga teng emas.
3-hodisa. JSON dan kelgan sozlamalar birlashtiriladi:
bayroqlar = {1: "birinchi", True: "yoqilgan"}
bayroqlar # {1: 'yoqilgan'} — bitta kalit! is va == — ikki xil savol, va Python ularga turli mexanizmlar bilan javob beradi. == — foydalanuvchi yozadigan protokol, is — ko'rsatkichlarni taqqoslash. Konteynerlar esa ikkalasini birga ishlatadi. Bu darsda shu mexanizmlarni aniq ko'ramiz.
Bu darsda:
-
is— identifikatsiya,idbilan munosabati va bog'langan metod tuzog'i -
==protokoli: teskari metod,NotImplemented, identifikatsiyaga qaytish - Konteynerlar
isni==dan oldin tekshiradi - Teng, lekin turli qiymatlar:
1,1.0,True,-0.0va xesh NaN— o'ziga teng bo'lmagan qiymatisqachon to'g'ri:None, belgi obyektlari (sentinel), singletonlar, aniq tur tekshiruvi
2. Nazariya — chuqur tushuntirish
2.1. is — identifikatsiya
a is b — ikki nom bir xil obyektga ishora qiladimi. CPython'da bu ikki ko'rsatkichni solishtirish:
- yuklab bo'lmaydi — hech qanday maxsus metod chaqirilmaydi
- eng tez taqqoslash
- natija har doim
bool
a is b ≡ id(a) == id(b) — faqat ikkala obyekt bir vaqtda tirik bo'lsa (11.1-dars).
Bog'langan metod tuzog'i (10.17-dars):
a.metod is a.metod # False — har murojaatda yangi bog'langan metod obyekti
id(a.metod) == id(a.metod) # True — birinchisi o'lib, ikkinchisi o'sha manzilga tushdi
a.metod == a.metod # True — bir funksiya, bir nusxa2.2. == protokoli
a == b bajarilishi:
- Agar
type(b)—type(a)ning merosxo'ri bo'lib,__eq__ni qayta yozgan bo'lsa → avvalb.__eq__(a) - Aks holda
a.__eq__(b) - Natija
NotImplementedbo'lsa → teskarisi:b.__eq__(a) - Ikkalasi ham
NotImplementedbo'lsa →a is b(!=uchun —a is not b)
object.__eq__ ning o'zi taxminan:
def __eq__(self, boshqa):
return True if self is boshqa else NotImplementedOqibatlari:
__eq__yozilmagan klass nusxalari faqat o'ziga teng__eq__NotImplementedqaytarsa, oxirida baribir identifikatsiya tekshiriladi —e == e→True==hech qachonTypeErrorbermaydi (farqli turlar — shunchakiFalse);<esa beradi!=—__ne__yozilmagan bo'lsa,__eq__natijasining inkori (NotImplementedbo'lmasa)__eq__istalgan narsa qaytarishi mumkin — NumPy va so'rov quruvchilar (10.14-dars)
2.3. Konteynerlar is ni avval tekshiradi
C darajasida konteynerlar PyObject_RichCompareBool dan foydalanadi. U taqqoslashdan oldin identifikatsiyani tekshiradi:
def teng_mi(a, b): # konteyner ichidagi taqqoslash
return a is b or bool(a == b)Qayerda ishlatiladi:
| Amal | Oqibat |
|---|---|
x in royxat, royxat.index(x), .count(x), .remove(x) |
O'sha obyekt topiladi, __eq__ nima desa ham |
royxat1 == royxat2, kortej1 == kortej2 |
Elementlar juftma-juft — is yoki == |
dict va set qidiruvi |
Xesh mos kelsa → is, keyin == |
Shu sababli refleksivlik kafolatlanadi: konteyner ichidagi har element o'zini topadi — hatto nan yoki __eq__ har doim False qaytaradigan obyekt ham.
2.4. Teng, lekin turli qiymatlar
1 == 1.0 == True == Fraction(1) == Decimal(1) # True
0 == -0.0 == False # TruePython qoidasi: a == b bo'lsa, hash(a) == hash(b). Shuning uchun sonli turlar xeshi bir xil, va ular lug'at va to'plamda bitta kalit:
{1: "a", True: "b", 1.0: "c"} # {1: 'c'}
len({0, 0.0, -0.0, False}) # 1Qoida: birinchi kalit saqlanadi, qiymat oxirgisi.
Turlarni ajratish kerak bo'lsa — kalitga turni qo'shing: (type(x), x).
2.5. NaN — o'ziga teng bo'lmagan qiymat
IEEE 754 standarti bo'yicha NaN hech narsaga, hatto o'ziga ham teng emas:
nan = float("nan")
nan == nan # False
nan is nan # True
nan in [nan] # True — o'sha obyekt (2.3)
float("nan") in [float("nan")] # False — boshqa obyekt, == FalseTuzoqlar:
set(olchovlar)— har xilnanobyektlari alohida qoladisorted()—nanbo'lsa, tartib buziladi (har taqqoslashFalse)max/min—nanqayerda turganiga qarab natija o'zgaradilug'at[nan]— faqat o'sha obyekt bilan topiladi
math.isnan(x) bilan tekshiring, tozalashda nan larni oldindan ajrating.
2.6. is qachon to'g'ri
| Holat | Misol | Nega |
|---|---|---|
None |
if x is None: |
Yagona nusxa; __eq__ yuklangan obyektlarda == None aldashi mumkin |
| Belgi obyekti (sentinel) | if qiymat is YOQ: |
"berilmagan" ni None dan ajratish |
| Singletonlar | is NotImplemented, is ... |
Yagona nusxalar |
enum a'zolari |
if rang is Rang.QIZIL: |
Har a'zo yagona |
| Aniq tur | type(x) is int |
bool ni int dan ajratish (isinstance ajratmaydi) |
| "O'sha obyektmi?" | if eski is yangi: |
O'zgaruvchan obyekt nusxalanganmi yoki yo'q |
is noto'g'ri:
- sonlar, satrlar, kortejlar — qiymat taqqoslash uchun (keshlash va interning — 11.7-dars — tasodifiy natija beradi)
- hisoblash natijalari:
int("1000") is 1000→False
Python literal bilan is ni ko'rsa, ogohlantiradi: SyntaxWarning: "is" with 'int' literal. Did you mean "=="? (int, str, bytes, tuple, float literallari uchun).
2.7. Belgi obyekti (sentinel) naqshi
None — haqiqiy qiymat bo'lishi mumkin bo'lganda, "argument berilmagan" holatini ajratish uchun:
_YOQ = object()
def ol(lugat, kalit, sukut=_YOQ):
try:
return lugat[kalit]
except KeyError:
if sukut is _YOQ:
raise
return sukutYaxshiroq variant — tushunarli repr bilan:
class _Yoq:
_nusxa = None
def __new__(cls):
if cls._nusxa is None:
cls._nusxa = super().__new__(cls)
return cls._nusxa
def __repr__(self):
return "YOQ"
def __bool__(self):
return False
YOQ = _Yoq()Standart kutubxonada: dataclasses.MISSING, inspect.Parameter.empty, unittest.mock.sentinel.
3. Tez ma'lumotnoma
is
a is b bir obyektmi — yuklanmaydi, eng tez
a is b ≡ id(a) == id(b) (faqat ikkalasi tirik bo'lsa)
a.metod is a.metod → False==
merosxo'r o'ng operand → b.__eq__(a) avval
a.__eq__(b) → NotImplemented → b.__eq__(a) → NotImplemented → a is b
!= → __ne__ yoki not __eq__
object.__eq__: self is other yoki NotImplementedKonteynerlar
in, index, count, remove, list ==, dict/set qidiruv: a is b or a == b
nan in [nan] → True (o'sha obyekt)Teng qiymatlar
1 == 1.0 == True 0 == -0.0 hash teng → bitta kalit
{1: "a", True: "b"} → {1: 'b'} kalit (type(x), x) — ajratish uchunis to'g'ri
None sentinel NotImplemented / ... enum type(x) is K o'sha obyektmi4. Batafsil misollar
Misol 1 — == protokolini kuzatish
"""__eq__ chaqiruv tartibi, NotImplemented, identifikatsiyaga qaytish, merosxo'r ustuvorligi, !=."""
def kuzat(nom, qaytar):
def __eq__(self, boshqa):
print(f" {nom}.__eq__({type(boshqa).__name__}) → {qaytar!r}")
return qaytar
return __eq__
class Rad:
__eq__ = kuzat("Rad", NotImplemented)
__hash__ = object.__hash__
class Teng:
__eq__ = kuzat("Teng", True)
__hash__ = object.__hash__
class Bola(Rad):
__eq__ = kuzat("Bola", True)
__hash__ = object.__hash__
class Oddiy:
pass
print("=== 1. Ikkala tomon ham NotImplemented → identifikatsiya ===")
r1, r2 = Rad(), Rad()
print(" r1 == r1:")
print(f" → {r1 == r1}")
print(" r1 == r2:")
print(f" → {r1 == r2}")
print(" r1 != r1:")
print(f" → {r1 != r1}")
print("\n=== 2. Chap rad etsa, o'ng urinib ko'radi ===")
print(" Rad() == Teng():")
print(f" → {Rad() == Teng()}")
print("\n=== 3. Merosxo'r o'ngda bo'lsa — birinchi ===")
print(" Rad() == Bola():")
print(f" → {Rad() == Bola()}")
print("\n=== 4. __eq__ yozilmagan klass ===")
o1, o2 = Oddiy(), Oddiy()
print(f" o1 == o1: {o1 == o1}, o1 == o2: {o1 == o2}, o1 != o2: {o1 != o2}")
print(f" object.__eq__(o1, o1): {object.__eq__(o1, o1)}, object.__eq__(o1, o2): {object.__eq__(o1, o2)}")
print("\n=== 5. == hech qachon TypeError bermaydi, < beradi ===")
print(f" 5 == 'besh': {5 == 'besh'}, [1] == (1,): {[1] == (1,)}, None == 0: {None == 0}")
try:
5 < "besh"
except TypeError as e:
print(f" 5 < 'besh': TypeError: {e}")
print("\n=== 6. Bog'langan metod: is, id va == ===")
class Hisob:
def qoldiq(self):
return 0
h = Hisob()
print(f" h.qoldiq is h.qoldiq: {h.qoldiq is h.qoldiq}")
print(f" id(h.qoldiq) == id(h.qoldiq): {id(h.qoldiq) == id(h.qoldiq)} ⚠️ vaqtinchalik obyektlar")
print(f" h.qoldiq == h.qoldiq: {h.qoldiq == h.qoldiq}")
m1, m2 = h.qoldiq, h.qoldiq
print(f" ikkalasi tirik: id teng: {id(m1) == id(m2)}, is: {m1 is m2}")Natijaning muhim qismi:
=== 1. Ikkala tomon ham NotImplemented → identifikatsiya ===
r1 == r1:
Rad.__eq__(Rad) → NotImplemented
Rad.__eq__(Rad) → NotImplemented
→ True
r1 == r2:
Rad.__eq__(Rad) → NotImplemented
Rad.__eq__(Rad) → NotImplemented
→ False
r1 != r1:
Rad.__eq__(Rad) → NotImplemented
Rad.__eq__(Rad) → NotImplemented
→ False
=== 2. Chap rad etsa, o'ng urinib ko'radi ===
Rad() == Teng():
Rad.__eq__(Teng) → NotImplemented
Teng.__eq__(Rad) → True
→ True
=== 3. Merosxo'r o'ngda bo'lsa — birinchi ===
Rad() == Bola():
Bola.__eq__(Rad) → True
→ True
=== 4. __eq__ yozilmagan klass ===
o1 == o1: True, o1 == o2: False, o1 != o2: True
object.__eq__(o1, o1): True, object.__eq__(o1, o2): NotImplemented
=== 5. == hech qachon TypeError bermaydi, < beradi ===
5 == 'besh': False, [1] == (1,): False, None == 0: False
5 < 'besh': TypeError: '<' not supported between instances of 'int' and 'str'
=== 6. Bog'langan metod: is, id va == ===
h.qoldiq is h.qoldiq: False
id(h.qoldiq) == id(h.qoldiq): True ⚠️ vaqtinchalik obyektlar
h.qoldiq == h.qoldiq: True
ikkalasi tirik: id teng: False, is: FalseNima ko'rsatdi: 2.1, 2.2-bo'limlar.
Misol 2 — Konteynerlarda identifikatsiya qisqa yo'li
"""NaN va 'o'ziga teng bo'lmagan' obyektlar ro'yxat, kortej, to'plam va lug'atda."""
import math
class HechQachon:
"""__eq__ har doim False — o'ziga ham."""
def __eq__(self, boshqa):
return False
__hash__ = object.__hash__
def __repr__(self):
return "HechQachon()"
nan = float("nan")
h = HechQachon()
print("=== 1. To'g'ridan-to'g'ri taqqoslash ===")
print(f" nan == nan: {nan == nan}, nan is nan: {nan is nan}")
print(f" h == h: {h == h}, h is h: {h is h}")
print("\n=== 2. Konteyner ichida — avval is ===")
for nom, x, boshqa in [("nan", nan, float("nan")), ("h", h, HechQachon())]:
royxat = [1, x, 3]
print(f" {nom}: x in royxat={x in royxat}, royxat.index(x)={royxat.index(x)}, count={royxat.count(x)}, "
f"boshqa nusxa in royxat={boshqa in royxat}")
print(f" [x] == [x]: {[x] == [x]}, (x,) == (x,): {(x,) == (x,)}, [x] == [boshqa]: {[x] == [boshqa]}")
print("\n=== 3. To'plam va lug'at ===")
olchovlar = [12.5, nan, float("nan"), float("nan"), 12.5, nan]
print(f" set(olchovlar): {len(set(olchovlar))} ta element — {sorted(map(str, set(olchovlar)))}")
lugat = {nan: "birinchi nan"}
print(f" lugat[nan] (o'sha obyekt): {lugat.get(nan)!r}, lugat[float('nan')]: {lugat.get(float('nan'))!r}")
print("\n=== 4. ⚠️ Saralash va max/min ===")
qiymatlar = [3.0, nan, 1.0, 2.0]
print(f" sorted([3, nan, 1, 2]): {sorted(qiymatlar)}")
print(f" max([nan, 1, 2]): {max([nan, 1.0, 2.0])}, max([1, 2, nan]): {max([1.0, 2.0, nan])}")
print("\n=== 5. ✅ To'g'ri tozalash ===")
tozalangan = sorted({x for x in olchovlar if not math.isnan(x)})
nan_soni = sum(math.isnan(x) for x in olchovlar)
print(f" NaN siz noyob: {tozalangan}, NaN soni: {nan_soni}")
print(f" max NaN siz: {max(x for x in qiymatlar if not math.isnan(x))}")Natijaning muhim qismi:
=== 1. To'g'ridan-to'g'ri taqqoslash ===
nan == nan: False, nan is nan: True
h == h: False, h is h: True
=== 2. Konteyner ichida — avval is ===
nan: x in royxat=True, royxat.index(x)=1, count=1, boshqa nusxa in royxat=False
[x] == [x]: True, (x,) == (x,): True, [x] == [boshqa]: False
h: x in royxat=True, royxat.index(x)=1, count=1, boshqa nusxa in royxat=False
[x] == [x]: True, (x,) == (x,): True, [x] == [boshqa]: False
=== 3. To'plam va lug'at ===
set(olchovlar): 4 ta element — ['12.5', 'nan', 'nan', 'nan']
lugat[nan] (o'sha obyekt): 'birinchi nan', lugat[float('nan')]: None
=== 4. ⚠️ Saralash va max/min ===
sorted([3, nan, 1, 2]): [3.0, nan, 1.0, 2.0]
max([nan, 1, 2]): nan, max([1, 2, nan]): 2.0
=== 5. ✅ To'g'ri tozalash ===
NaN siz noyob: [12.5], NaN soni: 4
max NaN siz: 3.0Nima ko'rsatdi: 2.3, 2.5-bo'limlar. 2-bo'limda o'ziga teng bo'lmagan obyektlar ham ro'yxatda "topildi", chunki konteyner avval is ni tekshirdi; boshqa nan nusxasi esa topilmadi.
Misol 3 — Teng qiymatlar va xesh
"""1, 1.0, True, Fraction, Decimal — bir kalit; JSON sozlamalar tuzog'i; turlarni ajratish."""
from collections import Counter
from decimal import Decimal
from fractions import Fraction
print("=== 1. Teng va xeshi teng ===")
qiymatlar = [1, 1.0, True, Fraction(1), Decimal(1), complex(1, 0)]
for q in qiymatlar:
print(f" {q!r:14} == 1: {q == 1}, hash == hash(1): {hash(q) == hash(1)}, turi {type(q).__name__}")
print(f" 0 == -0.0 == False: {0 == -0.0 == False}, hash(-0.0) == hash(0): {hash(-0.0) == hash(0)}")
print("\n=== 2. Lug'at va to'plamda bitta kalit ===")
print(f" {{1: 'a', True: 'b', 1.0: 'c'}} → {dict([(1, 'a'), (True, 'b'), (1.0, 'c')])}")
print(f" {{True: 'b', 1: 'a'}} → {dict([(True, 'b'), (1, 'a')])} (birinchi kalit qoladi)")
print(f" len({{0, 0.0, -0.0, False}}) = {len({0, 0.0, -0.0, False})}")
print("\n=== 3. ⚠️ JSON sozlamalar ===")
manba1 = {"port": 8080, "debug": True, "workers": 1}
manba2 = {"port": 8080.0, "debug": 1, "workers": True}
teskari = {}
for manba in (manba1, manba2):
for kalit, qiymat in manba.items():
teskari.setdefault(qiymat, []).append(kalit)
print(f" qiymat → kalitlar: {teskari}")
print(" ⚠️ True va 1 bitta guruhga tushdi; 8080 va 8080.0 ham")
print("\n=== 4. Counter ham bir xil hisoblaydi ===")
javoblar = [True, 1, "1", 1.0, False, 0, "0"]
print(f" Counter: {Counter(javoblar)}")
print("\n=== 5. ✅ Turlarni ajratish: kalit (type, qiymat) ===")
ajratilgan = Counter((type(x).__name__, x) for x in javoblar)
print(f" {dict(ajratilgan)}")
teskari2 = {}
for manba in (manba1, manba2):
for kalit, qiymat in manba.items():
teskari2.setdefault((type(qiymat).__name__, qiymat), []).append(kalit)
print(f" qiymat → kalitlar: {teskari2}")Natijaning muhim qismi:
=== 1. Teng va xeshi teng ===
1 == 1: True, hash == hash(1): True, turi int
1.0 == 1: True, hash == hash(1): True, turi float
True == 1: True, hash == hash(1): True, turi bool
Fraction(1, 1) == 1: True, hash == hash(1): True, turi Fraction
Decimal('1') == 1: True, hash == hash(1): True, turi Decimal
(1+0j) == 1: True, hash == hash(1): True, turi complex
0 == -0.0 == False: True, hash(-0.0) == hash(0): True
=== 2. Lug'at va to'plamda bitta kalit ===
{1: 'a', True: 'b', 1.0: 'c'} → {1: 'c'}
{True: 'b', 1: 'a'} → {True: 'a'} (birinchi kalit qoladi)
len({0, 0.0, -0.0, False}) = 1
=== 3. ⚠️ JSON sozlamalar ===
qiymat → kalitlar: {8080: ['port', 'port'], True: ['debug', 'workers', 'debug', 'workers']}
⚠️ True va 1 bitta guruhga tushdi; 8080 va 8080.0 ham
=== 4. Counter ham bir xil hisoblaydi ===
Counter: Counter({True: 3, False: 2, '1': 1, '0': 1})
=== 5. ✅ Turlarni ajratish: kalit (type, qiymat) ===
{('bool', True): 1, ('int', 1): 1, ('str', '1'): 1, ('float', 1.0): 1, ('bool', False): 1, ('int', 0): 1, ('str', '0'): 1}
qiymat → kalitlar: {('int', 8080): ['port'], ('bool', True): ['debug', 'workers'], ('int', 1): ['workers', 'debug'], ('float', 8080.0): ['port']}Nima ko'rsatdi: 2.4-bo'lim. 3–4-bo'limlarda True, 1 va 1.0 ning bitta kalitga birlashishi ma'lumotni jim buzdi; kalitga tur qo'shilgach, guruhlar to'g'ri ajraldi.
Misol 4 — Amaliy: is to'g'ri va noto'g'ri ishlatilganda
Sozlamalar kutubxonasi: ol(kalit, sukut=...) "berilmagan" ni None dan ajratishi, eski qiymat bilan yangisi o'sha obyekt ekanini tekshirishi va sonlarni is bilan solishtirish xatosini ko'rsatishi kerak.
"""Sentinel, is None, o'sha obyekt tekshiruvi, type(x) is K; is bilan son/satr taqqoslash xatolari va SyntaxWarning."""
import warnings
from enum import Enum
class _Yoq:
_nusxa = None
def __new__(cls):
if cls._nusxa is None:
cls._nusxa = super().__new__(cls)
return cls._nusxa
def __repr__(self):
return "YOQ"
def __bool__(self):
return False
YOQ = _Yoq()
class Rejim(Enum):
ISHLAB_CHIQARISH = "prod"
SINOV = "test"
class Sozlamalar:
def __init__(self, **malumot):
self._malumot = dict(malumot)
def ol(self, kalit, sukut=YOQ):
qiymat = self._malumot.get(kalit, YOQ)
if qiymat is YOQ:
if sukut is YOQ:
raise KeyError(f"sozlama yo'q: {kalit}")
return sukut
return qiymat
def yangila(self, kalit, qiymat):
eski = self._malumot.get(kalit, YOQ)
if eski is qiymat:
return "o'sha obyekt — o'zgarish yo'q"
self._malumot[kalit] = qiymat
return "yangilandi" if eski is not YOQ else "qo'shildi"
s = Sozlamalar(proksi=None, portlar=[80, 443], rejim=Rejim.SINOV)
print("=== 1. Sentinel: None — haqiqiy qiymat ===")
print(f" ol('proksi'): {s.ol('proksi')!r} (None saqlangan)")
print(f" ol('kesh', sukut=None): {s.ol('kesh', sukut=None)!r}")
try:
s.ol("kesh")
except KeyError as e:
print(f" ol('kesh'): KeyError: {e}")
print(f" YOQ singleton: {_Yoq() is YOQ}, repr: {YOQ!r}, bool: {bool(YOQ)}")
print("\n=== 2. O'sha obyektmi yoki teng nusxami ===")
portlar = s.ol("portlar")
print(f" bir xil ro'yxat: {s.yangila('portlar', portlar)}")
print(f" teng, lekin nusxa: {s.yangila('portlar', [80, 443])}")
print(f" yangi kalit: {s.yangila('vaqt', 30)}")
print("\n=== 3. enum va aniq tur ===")
print(f" ol('rejim') is Rejim.SINOV: {s.ol('rejim') is Rejim.SINOV}")
for x in (1, True, 1.0):
print(f" {x!r:5} isinstance(x, int): {str(isinstance(x, int)):5} type(x) is int: {type(x) is int}")
print("\n=== 4. ❌ is bilan son va satrlar ===")
limit = 1000
javoblar = [int("1000"), 999 + 1, 1000]
for j in javoblar:
print(f" {j} == limit: {j == limit}, {j} is limit: {j is limit}")
OK = "ok"
kod = "".join(["o", "k"])
print(f" OK == kod: {OK == kod}, OK is kod: {OK is kod} (hisoblangan satr — boshqa obyekt)")
IKKI_YUZ = 200
kichik = int("200")
print(f" int('200') is IKKI_YUZ: {kichik is IKKI_YUZ} ⚠️ kichik sonlar o'lmas va yagona — tasodifan ishlaydi")
print("\n=== 5. SyntaxWarning: Python literal bilan is ni ogohlantiradi ===")
with warnings.catch_warnings(record=True) as ogohlantirishlar:
warnings.simplefilter("always")
for kod_matni in ["x is 1000", "x is 'ok'", "x is ()", "x is b'a'", "x is 1.5", "x is []", "x is None"]:
oldin = len(ogohlantirishlar)
compile(kod_matni, "<sinov>", "eval")
xabar = str(ogohlantirishlar[-1].message) if len(ogohlantirishlar) > oldin else "ogohlantirish yo'q"
print(f" {kod_matni:12} → {xabar}")Natijaning muhim qismi:
=== 1. Sentinel: None — haqiqiy qiymat ===
ol('proksi'): None (None saqlangan)
ol('kesh', sukut=None): None
ol('kesh'): KeyError: "sozlama yo'q: kesh"
YOQ singleton: True, repr: YOQ, bool: False
=== 2. O'sha obyektmi yoki teng nusxami ===
bir xil ro'yxat: o'sha obyekt — o'zgarish yo'q
teng, lekin nusxa: yangilandi
yangi kalit: qo'shildi
=== 3. enum va aniq tur ===
ol('rejim') is Rejim.SINOV: True
1 isinstance(x, int): True type(x) is int: True
True isinstance(x, int): True type(x) is int: False
1.0 isinstance(x, int): False type(x) is int: False
=== 4. ❌ is bilan son va satrlar ===
1000 == limit: True, 1000 is limit: False
1000 == limit: True, 1000 is limit: True
1000 == limit: True, 1000 is limit: True
OK == kod: True, OK is kod: False (hisoblangan satr — boshqa obyekt)
int('200') is IKKI_YUZ: True ⚠️ kichik sonlar o'lmas va yagona — tasodifan ishlaydi
=== 5. SyntaxWarning: Python literal bilan is ni ogohlantiradi ===
x is 1000 → "is" with 'int' literal. Did you mean "=="?
x is 'ok' → "is" with 'str' literal. Did you mean "=="?
x is () → "is" with 'tuple' literal. Did you mean "=="?
x is b'a' → "is" with 'bytes' literal. Did you mean "=="?
x is 1.5 → "is" with 'float' literal. Did you mean "=="?
x is [] → ogohlantirish yo'q
x is None → ogohlantirish yo'qNima ko'rsatdi: 2.6, 2.7-bo'limlar. 4-bo'limda int("1000") — ish vaqtida yaratilgan obyekt — is bilan mos kelmadi. 999 + 1 esa kompilyator tomonidan oldindan 1000 ga aylantirilib, modul konstantasi bilan birlashtirildi va tasodifan mos keldi (11.7-dars) — is natijasi kod qanday yozilganiga bog'liq bo'lib qoladi. x is [] va x is None ogohlantirishsiz: birinchisi har doim False, ikkinchisi to'g'ri.
5. To'g'ri va noto'g'ri tushunishlar
| Noto'g'ri fikr | To'g'risi |
|---|---|
"is — tezroq ==" |
Boshqa savol: bir obyektmi, tengmi emas |
"a is b har doim id(a) == id(b)" |
Faqat ikkalasi bir vaqtda tirik bo'lsa |
"__eq__ yozilmasa, == xato beradi" |
Identifikatsiyaga qaytadi |
"x == x har doim True" |
nan, o'z __eq__ i bilan — yo'q |
"Konteyner == bilan qidiradi" |
Avval is, keyin == |
"1, 1.0 va True — lug'atda turli kalitlar" |
Teng va xeshi teng — bitta kalit |
"set takrorlarni har doim olib tashlaydi" |
Turli nan obyektlari alohida qoladi |
"x is 1000 ishlasa — to'g'ri" |
Keshlash va konstanta birlashtirishiga bog'liq tasodif |
6. Keng tarqalgan xatolar va yechimlari
1. Son va satrlarni is bilan solishtirish
if holat is 200: ... # ❌ SyntaxWarning; hisoblangan qiymatlarda False bo'lishi mumkin
if holat == 200: ... # ✅2. None ni == bilan tekshirish
if natija == None: ... # ❌ __eq__ yuklangan obyektlarda (NumPy, so'rov quruvchi) noto'g'ri
if natija is None: ... # ✅3. None ni "berilmagan" deb ishlatish
def ol(kalit, sukut=None):
if sukut is None: # ❌ foydalanuvchi ataylab None bera olmaydi
raise KeyError(kalit)
_YOQ = object()
def ol(kalit, sukut=_YOQ): ... # ✅ sentinel4. nan larni set bilan tozalash
noyob = set(olchovlar) # ❌ har nan alohida
noyob = {x for x in olchovlar if not math.isnan(x)} # ✅ nan ni alohida hisoblang5. x == float("nan") bilan tekshirish
if x == float("nan"): ... # ❌ har doim False
if math.isnan(x): ... # ✅6. Aralash sonli kalitlar
hisob = {}
for javob in [True, 1, 1.0]:
hisob[javob] = hisob.get(javob, 0) + 1 # ❌ {True: 3}
hisob[(type(javob), javob)] = ... # ✅ tur bilan kalit7. bool ni int dan isinstance bilan ajratishga urinish
if isinstance(qiymat, int): ... # ❌ True ham o'tadi
if type(qiymat) is int: ... # ✅ aniq tur (yoki avval isinstance(qiymat, bool) ni tekshiring)8. id() ni vaqtinchalik obyektlar uchun taqqoslash
if id(obj.metod) == id(obj.metod): ... # ❌ har doim True — ma'nosiz
if obj.metod == boshqa.metod: ... # ✅ funksiya va nusxa bo'yicha7. Integratsiya — bu bilim qayerda kerak bo'ladi
- 3.11-dars (o'tilgan):
isva==bilan tanishuv - 6.13-dars (o'tilgan): xesh va lug'at kalitlari
- 8.12-dars (o'tilgan):
__eq__,__hash__,total_ordering - 10.14, 10.17-darslar (o'tilgan):
__eq__ifoda qaytaradigan DSL; bog'langan metodlar - 11.7-dars: interning —
isnega ba'zan "ishlaydi" - 13-qism:
is Nonebilan tur toraytirish,Literal, sentinel turlari - 17-qism: testlarda
assert x is Nonevaassert x == yfarqi - 24-qism: NumPy va pandas — elementlab
==,NaNvaisna()
8. Eng yaxshi amaliyotlar
Qiymat uchun
==, identifikatsiya uchunis. Hech qachon aksincha emas.None, sentinel,enumva singletonlar — faqatisbilan."Berilmagan" holati uchun sentinel —
Noneni haqiqiy qiymat sifatida qoldiring.NaNnimath.isnanbilan tekshiring va to'plam, saralash,maxdan oldin ajrating.Aralash sonli turlar kalit bo'lsa —
(type(x), x).__eq__yozganda__hash__ni ham yozing vaNotImplementedqaytaring (8.12-dars).Aniq tur kerak bo'lsa
type(x) is K, merosni qamrash kerak bo'lsaisinstance.SyntaxWarninglarni e'tiborsiz qoldirmang — ularisxatolarini oldindan ushlaydi.
9. Amaliy topshiriq
Vazifa 1: Natijani bashorat qiling
nan = float("nan")
class A:
def m(self):
pass
class E:
def __eq__(self, o):
return NotImplemented
class K:
def __eq__(self, o):
return False
__hash__ = object.__hash__
YOQ = object()
def ol(d, k, sukut=YOQ):
return d.get(k, sukut)
1. print(nan == nan, nan is nan)
2. print(nan in [nan], float("nan") in [float("nan")])
3. print({1: "a", True: "b"})
4. print(len({0, 0.0, -0.0, False}))
5. a = [1]
b = [1]
print(a == b, a is b)
6. a = A()
print(a.m is a.m, a.m == a.m)
7. e = E()
print(e == e, e == E())
8. k = K()
print(k == k, k in [k])
9. x = 1000
y = int("1000")
print(x == y, x is y)
10. print(type(True) is int, isinstance(True, int))
11. print(ol({"a": None}, "a") is YOQ, ol({}, "a") is YOQ)
12. print((1, 2) == [1, 2], [1, 2] == list((1, 2)))Javoblar
False TrueTrue False— birinchisi o'sha obyekt, ikkinchisi boshqanan{1: 'b'}— birinchi kalit, oxirgi qiymat1True FalseFalse True— har murojaatda yangi bog'langan metodTrue False— ikkala tomonNotImplemented→ identifikatsiyaFalse True— konteyner avvalisni tekshiradiTrue False— hisoblangan1000boshqa obyektFalse TrueFalse True—Nonesaqlangan qiymat, sentinel emasFalse True— kortej va ro'yxat teng emas
Vazifa 2: Xatolarni tuzating
1. def nol_mi(x):
return x is 0
2. def tozala(qiymatlar):
return sorted(set(qiymatlar)) # qiymatlar ichida nan bor
3. def sozlama(kalit, sukut=None):
if kalit in SOZLAMA:
return SOZLAMA[kalit]
if sukut is None:
raise KeyError(kalit)
return sukut
4. def ovozlar(javoblar): # javoblar: True/False va 1/0 aralash
return Counter(javoblar)
5. class Nuqta:
def __init__(self, x, y):
self.x, self.y = x, y
def __eq__(self, boshqa):
return self.x == boshqa.x and self.y == boshqa.y
nuqtalar = {Nuqta(1, 2)}Javoblar
1. def nol_mi(x):
return x == 0 # is — identifikatsiya, qiymat emas
2. def tozala(qiymatlar):
oddiylar = {x for x in qiymatlar if not (isinstance(x, float) and math.isnan(x))}
return sorted(oddiylar)
3. _YOQ = object()
def sozlama(kalit, sukut=_YOQ):
if kalit in SOZLAMA:
return SOZLAMA[kalit]
if sukut is _YOQ:
raise KeyError(kalit)
return sukut # endi sozlama("x", None) → None
4. def ovozlar(javoblar):
return Counter((type(j).__name__, j) for j in javoblar)
5. class Nuqta:
def __init__(self, x, y):
self.x, self.y = x, y
def __eq__(self, boshqa):
if not isinstance(boshqa, Nuqta):
return NotImplemented # boshqa turga AttributeError emas
return (self.x, self.y) == (boshqa.x, boshqa.y)
def __hash__(self): # __eq__ bor — xesh kerak, aks holda set da TypeError
return hash((self.x, self.y))Vazifa 3: teng_mi(a, b, *, qattiq=False)
Chuqur taqqoslash funksiyasini yozing:
- Ichma-ich
list,tuple,dict,setni rekursiv taqqoslasin qattiq=Truebo'lsa,1,1.0vaTrueni turli deb hisoblasinnanlarni teng deb hisoblash rejimi:nan_teng=True- Aylanma tuzilmalarda cheksiz rekursiyaga tushmasin (
idjuftliklari to'plami) - Farq topilsa — yo'lini qaytarsin:
["foydalanuvchilar", 3, "yosh"]
Vazifa 4: Sentinel kutubxonasi
sentinel("NOM")fabrika funksiyasini yozing: har nom uchun yagona,repr—<NOM>,bool—Falsepicklevacopydan keyin ham o'sha obyekt qolsin (10.16-dars,__reduce__)- Modul qayta yuklanganda (
importlib.reload) nima bo'lishini tekshiring va izohlang dataclasses.MISSINGvainspect.Parameter.emptyqanday yozilganini manba kodidan o'rganib, solishtiring
Vazifa 5: Ma'lumotlarni tozalash auditi
audit(royxat) funksiyasini yozing:
nanvaNonesonini hisoblasin- Teng, lekin turi farqli qiymatlarni topsin (
1va1.0vaTrue) -0.0ni ajratib ko'rsatsin (math.copysign)set(royxat)natijasining uzunligi bilan "haqiqiy noyob" qiymatlar soni farqini tushuntirsin- CSV dan o'qilgan ustun bilan sinab ko'ring
Vazifa 6: __eq__ protokoli tekshirgichi
Klassni oluvchi va uning __eq__ / __hash__ shartnomasini tekshiruvchi tekshir(klass, namunalar) yozing:
- Refleksivlik (
a == a), simmetriklik (a == b⇔b == a), tranzitivlik a == b⇒hash(a) == hash(b)- Boshqa turdagi obyekt bilan taqqoslash
TypeError/AttributeErrorbermasligi (NotImplemented) !===ning inkori ekanligi- Natijani jadval qilib chiqarsin; 8.12 va 10.14-darslardagi klasslarga qo'llang
Vazifa 7: O'ylash
Python'da == foydalanuvchi yozadigan protokol, is esa yuklanmaydi. Java'da == havolalarni taqqoslaydi, equals() qiymatni; JavaScript'da == tur o'zgartiradi, === esa yo'q; SQL'da NULL = NULL — NULL. Tenglik tushunchasi nega tillarda bunchalik farq qiladi va Python tanlovining afzalliklari va xavflari qanday?
Javob
Qisqa javob: "tenglik" bir necha xil savolni anglatadi — bir xil obyektmi, qiymati bir xilmi, ma'lum ma'noda almashtirsa bo'ladimi, qiymat ma'lummi. Har til bu savollarni turli operatorlarga turlicha taqsimlagan. Python o'qilishi eng muhim bo'lgan savolni (qiymat) eng qisqa operatorga (==) bergan va uni yuklanadigan qilgan, identifikatsiyani esa yuklanmaydigan is ga ajratgan. Bu tabiiy kod beradi, lekin foydalanuvchi __eq__ i refleksivlik, simmetriklik va xesh bilan moslik kabi qonunlarni buzishi mumkin.
1. Java: == va equals()
String a = new String("ok"), b = new String("ok");
a == b // false — havola
a.equals(b) // true — qiymat==— obyektlar uchun identifikatsiya (primitivlar uchun qiymat)- qiymat tengligi —
equals()metodi,hashCode()bilan juft - Identifikatsiya va qiymat aniq ajratilgan
- Eng ko'p kerak bo'ladigan savol (qiymat) eng uzun sintaksisga ega;
==bilan satrlarni solishtirish — klassik xato.Integerkeshlangani sababli==kichik sonlarda "ishlaydi" — Python'dagiistuzog'ining aynan o'zi
2. JavaScript: == va ===
0 == "" // true — tur o'zgartirish
0 === "" // false
NaN === NaN // false
Object.is(NaN, NaN) // true==— turlarni o'zgartiruvchi tenglik, murakkab qoidalar===— qat'iy tenglik, obyektlar uchun identifikatsiyaObject.is— "bir xil qiymat" (NaN o'ziga teng,+0va-0farqli)- Obyektlar uchun foydalanuvchi qiymat tengligini belgilash mexanizmi yo'q
3. SQL: uch qiymatli mantiq
NULL = NULL -- NULL (noma'lum), TRUE emas
NULL IS NULL -- TRUENULL— "noma'lum qiymat"; noma'lum narsa noma'lum narsaga tengmi — noma'lumIS NULL,IS DISTINCT FROM— alohida operatorlar- Python'dagi
NaNga o'xshash falsafa, lekin barcha turlar uchun
4. Python yondashuvi
==— qiymat tengligi,__eq__orqali to'liq boshqariladiis— identifikatsiya, yuklanmaydi- turlar orasida avtomatik konversiya yo'q (
1 == "1"→False), lekin sonli turlar orasida matematik tenglik bor (1 == 1.0) - konteynerlar
is or ==ishlatib, refleksivlikni kafolatlaydi
5. Afzalliklari
| Afzallik | Misol |
|---|---|
| Tabiiy o'qilish | if foydalanuvchi == admin: |
| Kengaytiriluvchanlik | Pul, Vektor, Sana o'z tengligini belgilaydi |
| DSL imkoniyati | NumPy a == b massiv, SQLAlchemy User.id == 5 ifoda |
| Identifikatsiya aniq | is yolg'on gapirmaydi — None, sentinel uchun ishonchli |
| Refleksivlik konteynerlarda | nan va g'alati __eq__ ro'yxatdagi elementni yo'qotmaydi |
6. Xavflari
| Xavf | Misol |
|---|---|
| Qonunlar buzilishi | Simmetrik bo'lmagan __eq__, xesh mos kelmasligi |
NaN |
x == x — False, set va sorted tuzoqlari |
| Sonli turlar birlashishi | {1, True, 1.0} — bitta element |
is noto'g'ri ishlatilishi |
Keshlangan kichik sonlar va interning tasodifan "ishlaydi" |
DSL __eq__ |
bool ga aylanmaydigan natija in, index, assert ni buzadi |
7. Amaliy xulosa
==— qiymat,is— identifikatsiya;isni faqat singletonlar va "o'sha obyektmi" savoli uchun ishlating- O'z
__eq__ingizni yozganda uni ekvivalentlik munosabati (refleksiv, simmetrik, tranzitiv) va xesh bilan mos qiling NaNvaNULLkabi "noma'lum" qiymatlarni alohida funksiyalar bilan tekshiring- Boshqa tillardan kelgan odatlarga (Java'dagi
==, JavaScript'dagi tur o'zgartirish) Python'da tayanmang
8. Xulosa
- Tenglik bir nechta savolni anglatadi va tillar ularni turlicha taqsimlaydi
- Java identifikatsiyani
==ga, JavaScript tur o'zgartirishni==ga, SQL noma'lumlikniNULLga bergan - Python qiymat tengligini yuklanadigan
==ga, identifikatsiyani yuklanmaydiganisga ajratgan - Bu tabiiy va kengaytiriladigan kod beradi, lekin foydalanuvchi
__eq__i qonunlarni buzishi mumkin - Konteynerlarning
is or ==qoidasi refleksivlikni saqlaydi —NaNkabi istisnolarga qaramay
Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.
Xulosa
Bu darsda identifikatsiya va tenglikni chuqur solishtirdik.
Eng muhim uch fikr:
is— identifikatsiya,==— protokol.isko'rsatkichlarni solishtiradi, yuklanmaydi vaid(a) == id(b)ga faqat ikkala obyekt tirik bo'lganda teng — bog'langan metodlar buni yaqqol ko'rsatadi.==esa__eq__ni chaqiradi: merosxo'r o'ng operand birinchi,NotImplementedbo'lsa teskari tomon, ikkalasi rad etsa — identifikatsiya. Shuning uchun__eq__yozilmagan obyektlar faqat o'ziga teng va==hech qachonTypeErrorbermaydi.Konteynerlar
is or ==qoidasi bilan ishlaydi.in,index,count, ro'yxat va kortejlarni solishtirish hamda lug'at qidiruvi avval identifikatsiyani tekshiradi. Shu tufaylinan in [nan]→True, lekin boshqanannusxasi topilmaydi vasetbir nechtananni saqlab qoladi. Teng sonli qiymatlar (1,1.0,True,-0.0) esa xeshi teng bo'lgani uchun lug'atda bitta kalitga birlashadi.isfaqat identifikatsiya savoli uchun.None, sentinel obyektlar,NotImplemented,enuma'zolari, aniq tur tekshiruvi (type(x) is int) va "o'sha obyektmi?" —isning to'g'ri joyi. Sonlar va satrlar uchuniskeshlash tufayli tasodifan ishlaydi va hisoblangan qiymatlarda buziladi — Python literal bilanisni ko'rgandaSyntaxWarningberadi. "Berilmagan" holati uchunNoneo'rniga sentinel ishlating.
Keyingi darsda havola semantikasini o'rganamiz: tayinlash, argument uzatish, o'zgaruvchan va o'zgarmas obyektlar, taxalluslar va nusxalash — "Python qiymat bo'yicha uzatadimi yoki havola bo'yicha?" degan savolga aniq javob.
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!