Bỏ qua để đến nội dung

{} là dict, không phải set!

# Tạo set với các phần tử
my_set = {1, 2, 3}
print(type(my_set)) # <class 'set'>
# Vậy tạo set rỗng cũng dùng {}?
empty = {}
print(type(empty)) # <class 'dict'> <- What the Python?!

Tại sao {1, 2, 3} là set nhưng {} lại là dict?! 🤔

Python được tạo ra năm 1991, Dictionary (dict) đã có từ đầu và sử dụng cú pháp {}.

Set (set) chỉ được thêm vào Python 2.4 (năm 2004), 13 năm sau!

# Dictionary - Có từ Python 1.0 (1991)
my_dict = {"key": "value"}
# Set - Thêm vào Python 2.4 (2004)
my_set = {1, 2, 3}

Khi set được thêm vào, {} đã được dùng cho dict rỗng. Để tránh breaking changes (phá vỡ code cũ), Python giữ nguyên {} = dict rỗng.

# Cách 1: Dùng {}
empty_dict = {}
print(type(empty_dict)) # <class 'dict'>
# Cách 2: Dùng dict()
empty_dict = dict()
print(type(empty_dict)) # <class 'dict'>
# Cả 2 cách đều OK
# KHÔNG THỂ dùng {}
empty_set = {} # ❌ Đây là dict, không phải set!
# PHẢI dùng set()
empty_set = set()
print(type(empty_set)) # <class 'set'> ✅
# Đây là CÁCH DUY NHẤT để tạo set rỗng
# Set - chỉ có values
my_set = {1, 2, 3}
print(my_set) # {1, 2, 3}
# Dict - có key:value pairs
my_dict = {"a": 1, "b": 2, "c": 3}
print(my_dict) # {'a': 1, 'b': 2, 'c': 3}
# Python phân biệt bằng dấu :
# - Không có : → Set
# - Có : → Dict
# Set rỗng - PHẢI dùng constructor
empty_set = set()
# Dict rỗng - Dùng {} hoặc constructor
empty_dict = {}
empty_dict = dict() # Cũng OK
# SAI - Vô tình tạo dict
def process_unique_items():
seen = {} # ❌ Đây là dict!
seen.add(1) # AttributeError: 'dict' object has no attribute 'add'
# ĐÚNG
def process_unique_items():
seen = set() # ✅
seen.add(1) # OK!
# SAI - Default là dict, không phải set
def track_ids(new_ids, existing={}): # ❌ {} là dict
existing.add(new_ids) # Lỗi!
# ĐÚNG
def track_ids(new_ids, existing=None):
if existing is None:
existing = set() # ✅
existing.add(new_ids)
from typing import Set, Dict
# Nếu dùng type hints, dễ phát hiện lỗi
def get_unique_items() -> Set[int]:
return {} # ❌ Type checker sẽ báo lỗi: Expected Set, got Dict
# ĐÚNG
def get_unique_items() -> Set[int]:
return set() # ✅
def find_unique_chars(text):
unique = set() # Bắt đầu với set rỗng
for char in text:
unique.add(char)
return unique
print(find_unique_chars("hello")) # {'h', 'e', 'l', 'o'}
def remove_duplicates(items):
seen = set() # Set rỗng để track
result = []
for item in items:
if item not in seen:
seen.add(item)
result.append(item)
return result
print(remove_duplicates([1, 2, 2, 3, 1, 4])) # [1, 2, 3, 4]
# Bắt đầu với set rỗng, sau đó union
all_tags = set()
for article in articles:
all_tags = all_tags.union(article.tags)
# Hoặc
all_tags = set()
for article in articles:
all_tags |= set(article.tags) # Union assignment
mystery = {}
# Debug
print(f"Type: {type(mystery)}") # <class 'dict'>
print(f"Is dict: {isinstance(mystery, dict)}") # True
print(f"Is set: {isinstance(mystery, set)}") # False
data = {}
# Nếu vô tình tạo dict thay vì set
data.add(1) # AttributeError: 'dict' object has no attribute 'add'
# → Lỗi này cho biết data là dict, không phải set!
# PyCharm, VS Code với Pylint sẽ cảnh báo
unique_items: Set[int] = {} # Warning: Expected Set, got dict
Mục đích Cú pháp Type Ví dụ
Set rỗng set() set s = set()
Set có phần tử {1, 2, 3} set s = {1, 2, 3}
Dict rỗng {} hoặc dict() dict d = {}
Dict có phần tử {"a": 1} dict d = {"a": 1}
# Set comprehension - Không có :
squares_set = {x**2 for x in range(5)}
print(squares_set) # {0, 1, 4, 9, 16}
print(type(squares_set)) # <class 'set'>
# Dict comprehension - Có :
squares_dict = {x: x**2 for x in range(5)}
print(squares_dict) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
print(type(squares_dict)) # <class 'dict'>
# Comprehension rỗng?
# - Set: {x for x in []} → set() (rỗng)
# - Dict: {x: x for x in []} → {} (rỗng)
s = set()
s.add(1) # ✅ Set có
s.remove(1) # ✅ Set có
s.discard(1) # ✅ Set có
s.union({2, 3}) # ✅ Set có
d = {}
d["key"] = "value" # ✅ Dict có
d.get("key") # ✅ Dict có
d.keys() # ✅ Dict có
d.values() # ✅ Dict có
d.items() # ✅ Dict có
# 1. Luôn dùng set() cho set rỗng
unique_items = set() # ✅ Rõ ràng
# 2. Dùng type hints
from typing import Set
def get_tags() -> Set[str]:
return set() # ✅
# 3. Kiểm tra type khi debug
if not isinstance(data, set):
raise TypeError(f"Expected set, got {type(data)}")
# 1. Dùng {} cho set rỗng
unique_items = {} # ❌ Nhầm lẫn!
# 2. Không kiểm tra type
def process(data):
data.add(1) # ❌ Nếu data là dict sẽ lỗi
# 3. Mixed types không rõ ràng
def create_collection(is_unique):
return set() if is_unique else {} # ❌ Confusing
  • 1991: Python ra đời, dict dùng {}
  • 2004: Python 2.4 - Set được thêm vào
  • Vấn đề: {} đã được dùng cho dict rỗng
  • Giải pháp:
    • Giữ {} = dict rỗng (backward compatibility)
    • Dùng set() cho set rỗng
    • Dùng {1, 2, 3} cho set có phần tử (phân biệt bằng không có :)
# Nếu thay đổi {} thành set:
# - Hàng triệu dòng code cũ sẽ bị hỏng
# - Dict rỗng phải dùng dict() (không tiện)
# - Breaking change quá lớn
Cú pháp Kiểu Ghi chú
{} dict Dict rỗng
{1, 2, 3} set Set với phần tử
{"a": 1} dict Dict với key:value
set() set Set rỗng (cách duy nhất)
dict() dict Dict rỗng (giống {})

{} là dict, không phải set!

  • ✅ Set rỗng: set() (cách DUY NHẤT)
  • ✅ Dict rỗng: {} hoặc dict()
  • 🔍 Python phân biệt set/dict bằng dấu :
    • Không có : → Set: {1, 2, 3}
    • : → Dict: {"a": 1, "b": 2}

Tip: Nhớ rằng dictionary “có trước” nên “chiếm” được {}!