Bài 3 · Cơ bản · 20 phút· Cập nhật 11/06/2026
Biến, đối tượng & tham chiếu
Biên soạn bởi Nguyễn Anh Tuấn
Trong Python mọi thứ là object: biến là “nhãn” tham chiếu (reference) tới object; id()/is/==; mutable vs immutable và bẫy aliasing khi sao chép list.
Một sự thật nền tảng: trong Python, mọi thứ đều là object - int, str, list, thậm chí cả hàm cũng là object. Mỗi object có ba thứ: một danh tính (identity, do id() cho biết), một kiểu (type), và một giá trị:
type.py
print(type(5))
print(type("hi"))
print(type([1, 2])) Kết quả khi chạy
<class 'int'> <class 'str'> <class 'list'>
- ▸int, str, list, dict… và cả hàm - tất cả là object trên “heap”.
- ▸Mỗi object có: identity (id), type (kiểu), value (giá trị).
- ▸type(x) cho biết kiểu; id(x) cho biết identity.
Đây là điểm khác C quan trọng nhất. Ở C, biến là một cái hộp chứa giá trị. Ở Python, biến là một cái nhãn được buộc vào một object. Lệnh a = [1, 2, 3] tạo object list rồi cho tên a trỏ tới nó. Bấm qua từng bước để xem nhãn & object:
- ▸Gán (=) buộc một TÊN vào một object - không “bỏ giá trị vào hộp”.
- ▸b = a tạo thêm một nhãn trỏ tới CÙNG object (không sao chép).
- ▸id() là identity object; nhiều tên cùng object thì cùng id().
Vì b = a không sao chép, đổi qua b sẽ thấy ở a - nếu object mutable như list (chọn chương trình “List: cùng object” ở công cụ trên):
aliasing.py
a = [1, 2, 3]
b = a # b tro CUNG object voi a
b.append(4) # doi list TAI CHO
print(a) # a cung thay doi! Kết quả khi chạy
[1, 2, 3, 4]
Muốn một bản sao riêng
Immutable (bất biến): int, float, bool, str, tuple - không đổi được, mọi “thay đổi” tạo object MỚI. Mutable (khả biến): list, dict, set - đổi tại chỗ. Vì int immutable, ví dụ dưới không có bẫy aliasing (chọn “Int: bất biến” ở công cụ):
rebind.py
x = 5
y = x # y tro cung object voi x
y = y + 1 # int BAT BIEN -> tao object MOI (6)
print(x, y) # x van la 5 Kết quả khi chạy
5 6
- ▸Immutable: int, float, bool, str, tuple - “sửa” = tạo object mới.
- ▸Mutable: list, dict, set - đổi tại chỗ, mọi nhãn cùng trỏ đều thấy.
- ▸Aliasing chỉ “gây bất ngờ” với object mutable.
Hai câu hỏi khác nhau: == hỏi “cùng giá trị?”, còn is hỏi “cùng MỘT object?” (cùng id). Hai list bằng nhau về giá trị vẫn là hai object khác nhau (chọn “is vs ==” ở công cụ để xem):
is_eq.py
p = [1, 2]
q = [1, 2]
print(p == q) # True - cung gia tri
print(p is q) # False - khac object (khac id) Kết quả khi chạy
True False
Quy tắc vàng
Bước 3 cho thấy b = a là CÙNG object → sửa a thì b đổi theo. Muốn một bản RIÊNG (độc lập), phải SAO CHÉP:
copy.py
a = [1, 2, 3]
b = a # ALIAS: cung mot object
c = a[:] # ban SAO (slice toan bo)
d = a.copy() # ban SAO
a.append(99)
print(b) # [1, 2, 3, 99] <- doi theo a
print(c, d) # [1, 2, 3] [1, 2, 3] <- doc lap Kết quả khi chạy
[1, 2, 3, 99] [1, 2, 3] [1, 2, 3]
Bản nông (shallow) vs bản sâu (deep)
- ▸b = a chia sẻ object; muốn bản riêng: a[:], a.copy(), list(a), dict(d), set(s).
- ▸Sao chép nông chỉ tách tầng ngoài; dữ liệu lồng nhau vẫn dùng chung.
- ▸copy.deepcopy() sao chép sâu mọi tầng - dùng khi cấu trúc lồng nhau.
Câu hỏi thường gặp
Không. Trong C, biến là một ô nhớ CHỨA giá trị. Trong Python, biến là một TÊN (nhãn) được “buộc” vào một object nằm trên heap. a = 5 không bỏ số 5 vào ô a; nó tạo object int 5 rồi cho tên a trỏ tới object đó. Nhiều tên có thể cùng trỏ một object.
id(x) trả về identity (danh tính) của object - một số duy nhất, không đổi trong suốt đời object. Ở CPython nó chính là địa chỉ bộ nhớ. Hai tên trỏ cùng object thì id() bằng nhau; đó là điều toán tử is kiểm tra.
== hỏi “hai object có CÙNG GIÁ TRỊ không?”. is hỏi “có phải CÙNG MỘT object không?” (cùng id). Hai list [1,2] và [1,2] thì == là True nhưng is là False (hai object khác nhau, tình cờ bằng giá trị). Quy tắc: so sánh giá trị thì dùng ==; chỉ dùng is cho None (x is None).
CPython tạo sẵn và dùng lại (cache) các int nhỏ từ −5 đến 256, nên 256 is 256 ra True. Nhưng đây là CHI TIẾT CÀI ĐẶT, không nên dựa vào - Python còn cảnh báo nếu bạn dùng is với int/str trực tiếp. Muốn so giá trị, LUÔN dùng ==.
Tick những điều em tự tin làm được. Càng lên cao, em càng hiểu sâu.
Trả lời vài câu để chắc rằng em đã nắm bài.
Trong Python, một biến (tên) thực chất là gì?
- 1
Bẫy aliasing
Đoán kết quả rồi chạy:
a = [1, 2, 3]; b = a; b.append(4); print(a). Vì sao?Hoàn thành khi:
[1, 2, 3, 4]-avàbcùng trỏ MỘT list;appendđổi list tại chỗ nênacũng thấy. - 2
Số thì an toàn
Chạy:
x = 5; y = x; y = y + 1; print(x, y). Vì saoxkhông đổi?Hoàn thành khi: 5 6 - int immutable;
y + 1tạo object MỚI và buộcyvào nó,xvẫn trỏ object 5. - 3
is hay ==
Với
p = [1, 2]vàq = [1, 2], dự đoánp == qvàp is q. Dùng công cụ Bước 5 để kiểm.Hoàn thành khi:
p == qlàTrue(cùng giá trị);p is qlàFalse(khác object). - 4
Sao chép thật
Sửa bài “aliasing” để đổi
bKHÔNG ảnh hưởnga.Hoàn thành khi: Dùng
b = a.copy()(hoặclist(a)/a[:]); khi đób.append(4)không đổia. - 5
Mọi thứ là object
In
typecủa 5, "hi",[1, 2]và của chính hàmprint. Nhận xét?Hoàn thành khi:
type(5)=int,type('hi')=str,type([1,2])=list,type(print)=builtin_function_or_method- đến hàm cũng là object. - 6
Chỉ is với None
Vì sao nên viết
if x is Nonethay vìif x == None?Hoàn thành khi:
Nonelà object DUY NHẤT (singleton);isso identity nhanh & đúng tuyệt đối, không phụ thuộc__eq__củax.