IlmHamroh
Python kursi/Obyekt modeli va xotira2/10-dars27 daqiqa
Mundarija (21)

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:

python
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:

python
noyob = set(olchovlar)            # [nan, nan, nan, 12.5, ...]

Natijada uchta nan qoladi — ular bir-biriga teng emas.

3-hodisa. JSON dan kelgan sozlamalar birlashtiriladi:

python
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, id bilan munosabati va bog'langan metod tuzog'i
  • == protokoli: teskari metod, NotImplemented, identifikatsiyaga qaytish
  • Konteynerlar is ni == dan oldin tekshiradi
  • Teng, lekin turli qiymatlar: 1, 1.0, True, -0.0 va xesh
  • NaN — o'ziga teng bo'lmagan qiymat
  • is qachon 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):

python
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 nusxa

2.2. == protokoli

a == b bajarilishi:

  1. Agar type(b) — type(a) ning merosxo'ri bo'lib, __eq__ ni qayta yozgan bo'lsa → avval b.__eq__(a)
  2. Aks holda a.__eq__(b)
  3. Natija NotImplemented bo'lsa → teskarisi: b.__eq__(a)
  4. Ikkalasi ham NotImplemented bo'lsa → a is b (!= uchun — a is not b)

object.__eq__ ning o'zi taxminan:

python
def __eq__(self, boshqa):
    return True if self is boshqa else NotImplemented

Oqibatlari:

  • __eq__ yozilmagan klass nusxalari faqat o'ziga teng
  • __eq__ NotImplemented qaytarsa, oxirida baribir identifikatsiya tekshiriladi — e == e → True
  • == hech qachon TypeError bermaydi (farqli turlar — shunchaki False); < esa beradi
  • != — __ne__ yozilmagan bo'lsa, __eq__ natijasining inkori (NotImplemented bo'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:

python
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

python
1 == 1.0 == True == Fraction(1) == Decimal(1)     # True
0 == -0.0 == False                                 # True

Python 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:

python
{1: "a", True: "b", 1.0: "c"}      # {1: 'c'}
len({0, 0.0, -0.0, False})          # 1

Qoida: 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:

python
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, == False

Tuzoqlar:

  • set(olchovlar) — har xil nan obyektlari alohida qoladi
  • sorted() — nan bo'lsa, tartib buziladi (har taqqoslash False)
  • max/min — nan qayerda turganiga qarab natija o'zgaradi
  • lug'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:

python
_YOQ = object()

def ol(lugat, kalit, sukut=_YOQ):
    try:
        return lugat[kalit]
    except KeyError:
        if sukut is _YOQ:
            raise
        return sukut

Yaxshiroq variant — tushunarli repr bilan:

python
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 NotImplemented

Konteynerlar

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 uchun

is to'g'ri

None   sentinel   NotImplemented / ...   enum   type(x) is K   o'sha obyektmi

4. Batafsil misollar

Misol 1 — == protokolini kuzatish

python
"""__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:

text
=== 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: False

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

Misol 2 — Konteynerlarda identifikatsiya qisqa yo'li

python
"""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:

text
=== 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.0

Nima 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

python
"""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:

text
=== 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.

python
"""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:

text
=== 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'q

Nima 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

python
if holat is 200: ...              # ❌ SyntaxWarning; hisoblangan qiymatlarda False bo'lishi mumkin
if holat == 200: ...              # ✅

2. None ni == bilan tekshirish

python
if natija == None: ...            # ❌ __eq__ yuklangan obyektlarda (NumPy, so'rov quruvchi) noto'g'ri
if natija is None: ...            # ✅

3. None ni "berilmagan" deb ishlatish

python
def ol(kalit, sukut=None):
    if sukut is None:             # ❌ foydalanuvchi ataylab None bera olmaydi
        raise KeyError(kalit)

_YOQ = object()
def ol(kalit, sukut=_YOQ): ...    # ✅ sentinel

4. nan larni set bilan tozalash

python
noyob = set(olchovlar)            # ❌ har nan alohida

noyob = {x for x in olchovlar if not math.isnan(x)}   # ✅ nan ni alohida hisoblang

5. x == float("nan") bilan tekshirish

python
if x == float("nan"): ...         # ❌ har doim False
if math.isnan(x): ...             # ✅

6. Aralash sonli kalitlar

python
hisob = {}
for javob in [True, 1, 1.0]:
    hisob[javob] = hisob.get(javob, 0) + 1    # ❌ {True: 3}

hisob[(type(javob), javob)] = ...             # ✅ tur bilan kalit

7. bool ni int dan isinstance bilan ajratishga urinish

python
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

python
if id(obj.metod) == id(obj.metod): ...    # ❌ har doim True — ma'nosiz
if obj.metod == boshqa.metod: ...         # ✅ funksiya va nusxa bo'yicha

7. Integratsiya — bu bilim qayerda kerak bo'ladi

  • 3.11-dars (o'tilgan): is va == 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 — is nega ba'zan "ishlaydi"
  • 13-qism: is None bilan tur toraytirish, Literal, sentinel turlari
  • 17-qism: testlarda assert x is None va assert x == y farqi
  • 24-qism: NumPy va pandas — elementlab ==, NaN va isna()

8. Eng yaxshi amaliyotlar

  1. Qiymat uchun ==, identifikatsiya uchun is. Hech qachon aksincha emas.

  2. None, sentinel, enum va singletonlar — faqat is bilan.

  3. "Berilmagan" holati uchun sentinel — None ni haqiqiy qiymat sifatida qoldiring.

  4. NaN ni math.isnan bilan tekshiring va to'plam, saralash, max dan oldin ajrating.

  5. Aralash sonli turlar kalit bo'lsa — (type(x), x).

  6. __eq__ yozganda __hash__ ni ham yozing va NotImplemented qaytaring (8.12-dars).

  7. Aniq tur kerak bo'lsa type(x) is K, merosni qamrash kerak bo'lsa isinstance.

  8. SyntaxWarning larni e'tiborsiz qoldirmang — ular is xatolarini oldindan ushlaydi.


9. Amaliy topshiriq

Vazifa 1: Natijani bashorat qiling

python
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
  1. False True
  2. True False — birinchisi o'sha obyekt, ikkinchisi boshqa nan
  3. {1: 'b'} — birinchi kalit, oxirgi qiymat
  4. 1
  5. True False
  6. False True — har murojaatda yangi bog'langan metod
  7. True False — ikkala tomon NotImplemented → identifikatsiya
  8. False True — konteyner avval is ni tekshiradi
  9. True False — hisoblangan 1000 boshqa obyekt
  10. False True
  11. False True — None saqlangan qiymat, sentinel emas
  12. False True — kortej va ro'yxat teng emas

Vazifa 2: Xatolarni tuzating

python
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
python
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:

  1. Ichma-ich list, tuple, dict, set ni rekursiv taqqoslasin
  2. qattiq=True bo'lsa, 1, 1.0 va True ni turli deb hisoblasin
  3. nan larni teng deb hisoblash rejimi: nan_teng=True
  4. Aylanma tuzilmalarda cheksiz rekursiyaga tushmasin (id juftliklari to'plami)
  5. Farq topilsa — yo'lini qaytarsin: ["foydalanuvchilar", 3, "yosh"]

Vazifa 4: Sentinel kutubxonasi

  1. sentinel("NOM") fabrika funksiyasini yozing: har nom uchun yagona, repr — <NOM>, bool — False
  2. pickle va copy dan keyin ham o'sha obyekt qolsin (10.16-dars, __reduce__)
  3. Modul qayta yuklanganda (importlib.reload) nima bo'lishini tekshiring va izohlang
  4. dataclasses.MISSING va inspect.Parameter.empty qanday yozilganini manba kodidan o'rganib, solishtiring

Vazifa 5: Ma'lumotlarni tozalash auditi

audit(royxat) funksiyasini yozing:

  1. nan va None sonini hisoblasin
  2. Teng, lekin turi farqli qiymatlarni topsin (1 va 1.0 va True)
  3. -0.0 ni ajratib ko'rsatsin (math.copysign)
  4. set(royxat) natijasining uzunligi bilan "haqiqiy noyob" qiymatlar soni farqini tushuntirsin
  5. 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:

  1. Refleksivlik (a == a), simmetriklik (a == b ⇔ b == a), tranzitivlik
  2. a == b ⇒ hash(a) == hash(b)
  3. Boshqa turdagi obyekt bilan taqqoslash TypeError/AttributeError bermasligi (NotImplemented)
  4. != == ning inkori ekanligi
  5. 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()

java
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. Integer keshlangani sababli == kichik sonlarda "ishlaydi" — Python'dagi is tuzog'ining aynan o'zi

2. JavaScript: == va ===

javascript
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 identifikatsiya
  • Object.is — "bir xil qiymat" (NaN o'ziga teng, +0 va -0 farqli)
  • Obyektlar uchun foydalanuvchi qiymat tengligini belgilash mexanizmi yo'q

3. SQL: uch qiymatli mantiq

sql
NULL = NULL      -- NULL (noma'lum), TRUE emas
NULL IS NULL     -- TRUE
  • NULL — "noma'lum qiymat"; noma'lum narsa noma'lum narsaga tengmi — noma'lum
  • IS NULL, IS DISTINCT FROM — alohida operatorlar
  • Python'dagi NaN ga o'xshash falsafa, lekin barcha turlar uchun

4. Python yondashuvi

  • == — qiymat tengligi, __eq__ orqali to'liq boshqariladi
  • is — 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

  1. == — qiymat, is — identifikatsiya; is ni faqat singletonlar va "o'sha obyektmi" savoli uchun ishlating
  2. O'z __eq__ ingizni yozganda uni ekvivalentlik munosabati (refleksiv, simmetrik, tranzitiv) va xesh bilan mos qiling
  3. NaN va NULL kabi "noma'lum" qiymatlarni alohida funksiyalar bilan tekshiring
  4. Boshqa tillardan kelgan odatlarga (Java'dagi ==, JavaScript'dagi tur o'zgartirish) Python'da tayanmang

8. Xulosa

  1. Tenglik bir nechta savolni anglatadi va tillar ularni turlicha taqsimlaydi
  2. Java identifikatsiyani == ga, JavaScript tur o'zgartirishni == ga, SQL noma'lumlikni NULL ga bergan
  3. Python qiymat tengligini yuklanadigan == ga, identifikatsiyani yuklanmaydigan is ga ajratgan
  4. Bu tabiiy va kengaytiriladigan kod beradi, lekin foydalanuvchi __eq__ i qonunlarni buzishi mumkin
  5. Konteynerlarning is or == qoidasi refleksivlikni saqlaydi — NaN kabi istisnolarga qaramay

Nimani mustahkamlaydi: 2.1–2.7-bo'limlar.


Xulosa

Bu darsda identifikatsiya va tenglikni chuqur solishtirdik.

Eng muhim uch fikr:

  1. is — identifikatsiya, == — protokol. is ko'rsatkichlarni solishtiradi, yuklanmaydi va id(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, NotImplemented bo'lsa teskari tomon, ikkalasi rad etsa — identifikatsiya. Shuning uchun __eq__ yozilmagan obyektlar faqat o'ziga teng va == hech qachon TypeError bermaydi.

  2. Konteynerlar is or == qoidasi bilan ishlaydi. in, index, count, ro'yxat va kortejlarni solishtirish hamda lug'at qidiruvi avval identifikatsiyani tekshiradi. Shu tufayli nan in [nan] → True, lekin boshqa nan nusxasi topilmaydi va set bir nechta nan ni saqlab qoladi. Teng sonli qiymatlar (1, 1.0, True, -0.0) esa xeshi teng bo'lgani uchun lug'atda bitta kalitga birlashadi.

  3. is faqat identifikatsiya savoli uchun. None, sentinel obyektlar, NotImplemented, enum a'zolari, aniq tur tekshiruvi (type(x) is int) va "o'sha obyektmi?" — is ning to'g'ri joyi. Sonlar va satrlar uchun is keshlash tufayli tasodifan ishlaydi va hisoblangan qiymatlarda buziladi — Python literal bilan is ni ko'rganda SyntaxWarning beradi. "Berilmagan" holati uchun None o'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.

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!