Python 256 is 256 là True nhưng 257 is 257 lại False - vì sao?
is vs ==: vì sao 256 is 256 True mà 257 is 257 có thể False
Bài 3 - series "Python cho dân backend: nền tảng để lên level".
Câu đố làm nhiều người hoảng:
a = 256; b = 256
print(a is b) # True
a = 257; b = 257
print(a is b) # False (tùy ngữ cảnh chạy!)
Cùng kiểu so sánh, cùng hai số bằng nhau, mà 256 thì True, 257 thì False? Nếu bây đang dùng is để so giá trị thì đây là quả bom hẹn giờ.
is và == KHÔNG giống nhau
==so giá trị - gọi__eq__, hỏi "hai cái có bằng nhau không".isso identity - hỏi "có phải cùng một object trong bộ nhớ không" (cùngid()- đọc lại bài 2 qua có nói về chỗ object này).
Hai object khác nhau mà giá trị bằng -> == True nhưng is False. Đừng lẫn.
Giải cái đố: interning
CPython, để tiết kiệm, tạo sẵn và dùng chung (cache) các số nguyên nhỏ từ -5 tới 256. Nên a = 256 và b = 256 cùng trỏ về một object 256 dùng chung -> is ra True. Còn 257 nằm ngoài khoảng cache -> mỗi chỗ có thể là một object riêng -> is ra False.
Tương tự, một số chuỗi ngắn/giống tên biến cũng được intern (dùng chung) -> is đôi khi True với string. Nhưng đây là chi tiết hiện thực của CPython, đổi theo phiên bản/ngữ cảnh - tuyệt đối đừng dựa vào.
a = "hello"; b = "hello"
print(a is b) # thường True (interned) - nhưng đừng tin tưởng
print(a == b) # True - cái này mới đáng tin
Quy tắc: dùng cái nào khi nào
- So giá trị -> luôn dùng
==. Số, chuỗi, list, dict... muốn biết "có bằng nhau" thì==. ischỉ dùng cho singleton:is None,is True,is False, hoặc so với một sentinel object bây cố tình tạo. Mấy cái này chỉ có đúng một object trong cả chương trình, nênismới đúng nghĩa.
if x is None: # ĐÚNG
if x == None: # tránh (dùng được mà sai tinh thần)
if x is 5: # SAI - đừng dùng is cho số
Hệ quả: bug "chạy lúc test, sai lúc prod"
Đây là cái độc nhứt: if ma_loi is 200 chạy đúng khi test (số nhỏ, được cache) rồi sai âm thầm khi gặp số lớn ngoài khoảng cache. Bug phụ thuộc chi tiết hiện thực thì cực khó lần. Nhớ bài 1: ở đó qua viết gio_hang is None - đúng vì None là singleton; nếu lỡ tay viết is cho số/chuỗi thì dính bẫy này.
Checklist: bây nắm chưa?
==so cái gì,isso cái gì? (==so giá trị;isso identity - cùng một object không.)- Vì sao
256 is 256True mà257có thể False? (CPython cache sẵn int nhỏ -5..256; ngoài đó là object riêng.) - Có nên dựa vào string interning hông? (Hông nha - chi tiết hiện thực, đổi theo phiên bản.)
- So giá trị thì luôn dùng cái nào? (
==.) ischỉ nên dùng cho gì? (Singleton:None,True,False, sentinel.)- Vì sao
if x is 5nguy hiểm? (Đúng với số nhỏ được cache, sai với số lớn -> bug âm thầm.)
Bài tới: "Shallow vs deep copy - copy cái dict mà sửa bản sao thì bản gốc cũng đổi."
Bản gốc đăng tại Substack: https://quakebaynghe.substack.com/p/python-is-vs-equal-interning
All rights reserved