Giới thiệu về Dictionary trong Python

Python Tutorial | by Hoc Python

Tưởng tượng một cuốn từ điển trong đời thực, nơi mỗi từ (khóa) có một định nghĩa (giá trị) đi kèm, giúp bạn tra cứu thông tin một cách nhanh chóng và hiệu quả. Trong lập trình Python, Dictionary cũng hoạt động theo nguyên lý tương tự: nó cho phép chúng ta lưu trữ và quản lý dữ liệu dưới dạng các cặp khóa-giá trị (key-value pairs).

Trong bài viết này, mình sẽ cùng nhau tìm hiểu Dictionary từ những khái niệm cơ bản nhất đến cách sử dụng chúng để tổ chức dữ liệu một cách thông minh. Bạn sẽ hiểu tại sao Dictionary lại trở thành công cụ không thể thiếu trong nhiều ứng dụng Python, từ việc quản lý thông tin người dùng đến xây dựng các cấu trúc dữ liệu phức tạp. Hãy cùng bắt đầu hành trình tìm hiểu về kiểu dữ liệu độc đáo này nhé!

Dictionary là gì?

Dictionary (từ điển) trong Python là một kiểu dữ liệu dùng để lưu trữ các tập hợp dữ liệu dưới dạng cặp "khóa-giá trị" (key-value pairs). Mỗi giá trị được liên kết với một khóa duy nhất, và bạn có thể truy cập giá trị đó bằng cách sử dụng khóa tương ứng.

Hãy hình dung một cuốn từ điển ngoài đời thực:

Mỗi từ là một khóa (key).

Định nghĩa của từ đó là giá trị (value).

Khi bạn muốn tìm nghĩa của một từ, bạn sẽ tra cứu từ đó (khóa) và nhận được định nghĩa của nó (giá trị). Dictionary trong Python hoạt động y hệt như vậy, giúp chúng ta tổ chức dữ liệu một cách có ý nghĩa và dễ dàng truy xuất.

Ví dụ cơ bản:

# Tạo một dictionary lưu thông tin của một người
thong_tin_ca_nhan = {
    "ten": "Nguyen Van A",
    "tuoi": 25,
    "nghe_nghiep": "Lập trình viên",
    "thanh_pho": "Ha Noi"
}

print(thong_tin_ca_nhan)
# Output: {'ten': 'Nguyen Van A', 'tuoi': 25, 'nghe_nghiep': 'Lập trình viên', 'thanh_pho': 'Ha Noi'}

Trong ví dụ trên:

  • "ten", "tuoi", "nghe_nghiep", "thanh_pho" là các khóa (keys).

  • "Nguyen Van A", 25, "Lập trình viên", "Ha Noi" là các giá trị (values) tương ứng.

Đặc điểm chính của Dictionary

Không có thứ tự cụ thể (hoặc giữ thứ tự chèn từ Python 3.7 trở lên)

Trước Python phiên bản 3.7, các phần tử trong dictionary không được sắp xếp theo một thứ tự nhất định. Điều này có nghĩa là thứ tự bạn thêm các cặp khóa-giá trị có thể không phải là thứ tự mà chúng được lưu trữ hoặc hiển thị. Tuy nhiên, từ Python 3.7 trở đi, Dictionary được đảm bảo giữ nguyên thứ tự các phần tử được chèn vào (insertion-ordered).

Ví dụ:

my_dict = {"apple": 1, "banana": 2, "cherry": 3}
print(my_dict)
# Output (Python 3.7+): {'apple': 1, 'banana': 2, 'cherry': 3}
# Output (Python < 3.7 có thể khác): {'banana': 2, 'apple': 1, 'cherry': 3} (thứ tự có thể thay đổi)

another_dict = {}
another_dict["first"] = "Hello"
another_dict["second"] = "World"
another_dict["third"] = "Python"
print(another_dict)
# Output (Python 3.7+): {'first': 'Hello', 'second': 'World', 'third': 'Python'}

Mặc dù Python 3.7+ đã đảm bảo thứ tự chèn, nhưng khi bạn truy cập các phần tử, bạn vẫn nên dựa vào khóa chứ không phải vị trí (index) của chúng, vì đó là cách thiết kế chính của dictionary.

Có thể thay đổi (Mutable)

Dictionary là một kiểu dữ liệu có thể thay đổi (mutable). Điều này có nghĩa là sau khi bạn đã tạo một dictionary, bạn hoàn toàn có thể thêm các cặp khóa-giá trị mới, sửa đổi giá trị của các khóa hiện có, hoặc xóa bỏ các cặp khóa-giá trị.

Ví dụ:

sinh_vien = {
    "ma_sv": "SV001",
    "ten": "Tran Thi B",
    "diem_tb": 8.5
}

print("Dictionary ban đầu:", sinh_vien)

# Thêm một phần tử mới
sinh_vien["lop"] = "K10"
print("Sau khi thêm 'lop':", sinh_vien)

# Sửa đổi giá trị của một phần tử
sinh_vien["diem_tb"] = 9.0
print("Sau khi sửa 'diem_tb':", sinh_vien)

# Xóa một phần tử
del sinh_vien["ma_sv"]
print("Sau khi xóa 'ma_sv':", sinh_vien)

Khóa phải là duy nhất (Unique Keys)

Mỗi khóa trong một dictionary phải là duy nhất. Bạn không thể có hai khóa giống hệt nhau trong cùng một dictionary. Nếu bạn cố gắng gán một giá trị cho một khóa đã tồn tại, giá trị cũ của khóa đó sẽ bị ghi đè bằng giá trị mới.

Ví dụ:

san_pham = {
    "id": 101,
    "ten_sp": "Laptop",
    "gia": 1200
}

print("Dictionary ban đầu:", san_pham)

# Thêm một khóa mới (duy nhất)
san_pham["so_luong"] = 5
print("Sau khi thêm 'so_luong':", san_pham)

# Cố gắng thêm một khóa đã tồn tại - giá trị sẽ bị ghi đè
san_pham["gia"] = 1150 # Giá trị cũ của 'gia' (1200) sẽ bị thay bằng 1150
print("Sau khi ghi đè 'gia':", san_pham)

# Output:
# Dictionary ban đầu: {'id': 101, 'ten_sp': 'Laptop', 'gia': 1200}
# Sau khi thêm 'so_luong': {'id': 101, 'ten_sp': 'Laptop', 'gia': 1200, 'so_luong': 5}
# Sau khi ghi đè 'gia': {'id': 101, 'ten_sp': 'Laptop', 'gia': 1150, 'so_luong': 5}

Khóa phải là bất biến (Immutable Keys)

Các khóa trong dictionary phải là các đối tượng bất biến (immutable). Điều này có nghĩa là giá trị của khóa không thể thay đổi sau khi nó được tạo. Các kiểu dữ liệu bất biến phổ biến trong Python bao gồm:

  • Số (Integers, Floats)

  • Chuỗi (Strings)

  • Tuple

Các kiểu dữ liệu có thể thay đổi (mutable) như list hoặc dictionary khác không thể được sử dụng làm khóa.

Ví dụ về khóa hợp lệ (Immutable):

valid_keys_dict = {
    1: "Số nguyên là khóa",
    "hello": "Chuỗi là khóa",
    (1, 2, 3): "Tuple là khóa"
}
print(valid_keys_dict)
# Output: {1: 'Số nguyên là khóa', 'hello': 'Chuỗi là khóa', (1, 2, 3): 'Tuple là khóa'}

Ví dụ về khóa không hợp lệ (Mutable - sẽ gây lỗi):

# Đây là một ví dụ sẽ gây lỗi TypeError
try:
    invalid_keys_dict = {
        [1, 2]: "List không thể là khóa", # List là mutable
        {"a": 1}: "Dictionary không thể là khóa" # Dictionary là mutable
    }
    print(invalid_keys_dict)
except TypeError as e:
    print(f"Lỗi: {e}")
    # Output: Lỗi: unhashable type: 'list' (hoặc 'dict')

Lý do là các đối tượng mutable không "hashable" (không thể tạo ra một giá trị băm cố định), điều cần thiết để dictionary có thể nhanh chóng tìm kiếm các khóa.

Các phương thức Dictionary phổ biến khác trong Python

Python cung cấp một số phương thức tích hợp sẵn giúp bạn làm việc hiệu quả hơn với Dictionary. Ba phương thức quan trọng nhất là keys(), values(), và items().

keys(): Trả về tất cả các khóa

Phương thức keys() trả về một đối tượng "view" (kiểu dict_keys) chứa tất cả các khóa hiện có trong dictionary. Đối tượng này là một "view" động, nghĩa là nó sẽ tự động cập nhật nếu dictionary thay đổi.

Cú pháp:

cac_khoa = ten_dictionary.keys()

Ví dụ:

# Tạo một dictionary
nhan_vien = {
    "ma_nv": "NV001",
    "ho_ten": "Trần Văn D",
    "chuc_vu": "Quản lý",
    "luong": 15000000
}

# Lấy tất cả các khóa
cac_khoa_nhan_vien = nhan_vien.keys()
print("Các khóa:", cac_khoa_nhan_vien)
# Output: Các khóa: dict_keys(['ma_nv', 'ho_ten', 'chuc_vu', 'luong'])

# Bạn có thể chuyển đổi đối tượng dict_keys sang list để dễ dàng thao tác hơn
list_cac_khoa = list(cac_khoa_nhan_vien)
print("Các khóa dưới dạng list:", list_cac_khoa)
# Output: Các khóa dưới dạng list: ['ma_nv', 'ho_ten', 'chuc_vu', 'luong']

# Ví dụ về "view" động:
nhan_vien["phong_ban"] = "Kinh doanh" # Thêm một khóa mới
print("Các khóa sau khi thêm:", nhan_vien.keys())
# Output: Các khóa sau khi thêm: dict_keys(['ma_nv', 'ho_ten', 'chuc_vu', 'luong', 'phong_ban'])

values(): Trả về tất cả các giá trị

Phương thức values() trả về một đối tượng "view" (kiểu dict_values) chứa tất cả các giá trị hiện có trong dictionary. Tương tự như keys(), đối tượng này cũng là một "view" động.

Cú pháp:

cac_gia_tri = ten_dictionary.values()

Ví dụ:

# Tiếp tục với dictionary 'nhan_vien'
cac_gia_tri_nhan_vien = nhan_vien.values()
print("Các giá trị:", cac_gia_tri_nhan_vien)
# Output: Các giá trị: dict_values(['NV001', 'Trần Văn D', 'Quản lý', 15000000, 'Kinh doanh'])

# Chuyển đổi sang list
list_cac_gia_tri = list(cac_gia_tri_nhan_vien)
print("Các giá trị dưới dạng list:", list_cac_gia_tri)
# Output: Các giá trị dưới dạng list: ['NV001', 'Trần Văn D', 'Quản lý', 15000000, 'Kinh doanh']

items(): Trả về tất cả các cặp khóa-giá trị

Phương thức items() trả về một đối tượng "view" (kiểu dict_items) chứa tất cả các cặp khóa-giá trị trong dictionary. Mỗi cặp được biểu diễn dưới dạng một tuple (khóa, giá_trị). Đây cũng là một "view" động.

Cú pháp:

cac_cap_doi = ten_dictionary.items()

Ví dụ:

# Tiếp tục với dictionary 'nhan_vien'
cac_cap_nhan_vien = nhan_vien.items()
print("Các cặp khóa-giá trị:", cac_cap_nhan_vien)
# Output: Các cặp khóa-giá trị: dict_items([('ma_nv', 'NV001'), ('ho_ten', 'Trần Văn D'), ('chuc_vu', 'Quản lý'), ('luong', 15000000), ('phong_ban', 'Kinh doanh')])

# Chuyển đổi sang list các tuple
list_cac_cap = list(cac_cap_nhan_vien)
print("Các cặp khóa-giá trị dưới dạng list:", list_cac_cap)
# Output: Các cặp khóa-giá trị dưới dạng list: [('ma_nv', 'NV001'), ('ho_ten', 'Trần Văn D'), ('chuc_vu', 'Quản lý'), ('luong', 15000000), ('phong_ban', 'Kinh doanh')]

Ba phương thức này cực kỳ hữu ích khi bạn cần duyệt qua hoặc kiểm tra nội dung của một dictionary.

Lặp qua Dictionary trong Python

Việc lặp (iterate) qua các phần tử của Dictionary là một thao tác rất phổ biến để xử lý hoặc hiển thị dữ liệu. Python cung cấp nhiều cách để lặp qua các khóa, giá trị hoặc cả hai.

1. Lặp qua các khóa (mặc định)

Khi bạn lặp trực tiếp qua một dictionary bằng vòng lặp for, Python sẽ mặc định lặp qua các khóa của nó.

Cú pháp:

for key in ten_dictionary:
    # Do something with key
    # Để lấy giá trị, sử dụng ten_dictionary[key]

Ví dụ:

# Tạo một dictionary
cau_hinh = {
    "server": "localhost",
    "port": 8080,
    "database": "mydatabase",
    "username": "admin"
}

print("Lặp qua các khóa:")
for key in cau_hinh:
    print(f"Khóa: {key}")

# Output:
# Lặp qua các khóa:
# Khóa: server
# Khóa: port
# Khóa: database
# Khóa: username

Bạn cũng có thể kết hợp cách này với việc truy cập giá trị bằng khóa:

print("\nLặp qua khóa và giá trị (cách 1):")
for key in cau_hinh:
    value = cau_hinh[key]
    print(f"Khóa: {key}, Giá trị: {value}")

# Output:
# Lặp qua khóa và giá trị (cách 1):
# Khóa: server, Giá trị: localhost
# Khóa: port, Giá trị: 8080
# Khóa: database, Giá trị: mydatabase
# Khóa: username, Giá trị: admin

2. Lặp qua các giá trị

Để lặp trực tiếp qua các giá trị của dictionary, bạn sử dụng phương thức values().

Cú pháp:

for value in ten_dictionary.values():
    # Do something with value

Ví dụ:

print("\nLặp qua các giá trị:")
for value in cau_hinh.values():
    print(f"Giá trị: {value}")

# Output:
# Lặp qua các giá trị:
# Giá trị: localhost
# Giá trị: 8080
# Giá trị: mydatabase
# Giá trị: admin

3. Lặp qua cả khóa và giá trị

Đây là cách phổ biến và hiệu quả nhất khi bạn cần cả khóa và giá trị trong mỗi lần lặp. Bạn sử dụng phương thức items(), phương thức này trả về các cặp khóa-giá trị dưới dạng tuple, và bạn có thể "giải nén" (unpack) chúng trực tiếp vào hai biến trong vòng lặp for.

Cú pháp:

for key, value in ten_dictionary.items():
    # Do something with key and value

Ví dụ:

print("\nLặp qua cả khóa và giá trị (sử dụng items()):")
for key, value in cau_hinh.items():
    print(f"Khóa: {key}, Giá trị: {value}")

# Output:
# Lặp qua cả khóa và giá trị (sử dụng items()):
# Khóa: server, Giá trị: localhost
# Khóa: port, Giá trị: 8080
# Khóa: database, Giá trị: mydatabase
# Khóa: username, Giá trị: admin

Phương thức items() thường là lựa chọn tốt nhất khi bạn cần truy cập cả khóa và giá trị trong vòng lặp, vì nó rõ ràng và hiệu quả.

Tại sao nên sử dụng Dictionary?

Dictionary không chỉ là một kiểu dữ liệu để lưu trữ thông tin, mà còn là một công cụ mạnh mẽ giúp bạn tổ chức và quản lý dữ liệu một cách hiệu quả trong Python. Dưới đây là những lợi ích và ứng dụng chính khiến Dictionary trở nên không thể thiếu:

Lưu trữ dữ liệu có cấu trúc, dễ đọc và dễ quản lý

Một trong những ưu điểm lớn nhất của Dictionary là khả năng lưu trữ dữ liệu theo một cấu trúc rõ ràng và có ý nghĩa. Thay vì chỉ là một danh sách các giá trị, mỗi giá trị trong Dictionary được gắn với một "khóa" mô tả nội dung của nó. Điều này giúp mã của bạn dễ đọc, dễ hiểu và dễ bảo trì hơn rất nhiều.

Giải thích: Khi bạn có một tập hợp các thông tin liên quan, việc gán cho mỗi mảnh thông tin một cái tên (khóa) giúp bạn biết ngay đó là dữ liệu gì mà không cần phải nhớ vị trí của nó.

Ví dụ:

Hãy so sánh cách lưu trữ thông tin một người dùng bằng List và Dictionary:

# Lưu trữ thông tin người dùng bằng List (kém cấu trúc)
# Bạn phải nhớ vị trí của từng thông tin: [tên, tuổi, email, thành phố]
user_data_list = ["Alice", 30, "[email protected]", "New York"]

print(f"Tên người dùng (List): {user_data_list[0]}")
print(f"Email người dùng (List): {user_data_list[2]}")
# Để biết user_data_list[0] là gì, bạn phải nhớ thứ tự.

print("-" * 30)

# Lưu trữ thông tin người dùng bằng Dictionary (có cấu trúc, dễ đọc)
user_data_dict = {
    "ten": "Bob",
    "tuoi": 25,
    "email": "[email protected]",
    "thanh_pho": "London"
}

print(f"Tên người dùng (Dictionary): {user_data_dict['ten']}")
print(f"Email người dùng (Dictionary): {user_data_dict['email']}")
# Với Dictionary, bạn chỉ cần nhìn vào khóa là biết ngay đó là thông tin gì.

Rõ ràng, việc sử dụng user_data_dict['email'] dễ hiểu hơn nhiều so với user_data_list[2], đặc biệt khi cấu trúc dữ liệu trở nên phức tạp hơn.

Truy cập dữ liệu nhanh chóng bằng khóa

Dictionary được thiết kế để tối ưu hóa việc truy cập dữ liệu. Nhờ cơ chế băm (hashing) nội bộ, việc tìm kiếm một giá trị bằng khóa trong Dictionary diễn ra cực kỳ nhanh chóng, gần như là tức thời (độ phức tạp thời gian trung bình là ). Điều này làm cho Dictionary trở thành lựa chọn lý tưởng cho các tình huống cần tra cứu dữ liệu hiệu suất cao.

Giải thích: Khi bạn tra cứu một từ trong từ điển, bạn không cần phải đọc từng từ một từ đầu đến cuối. Thay vào đó, bạn mở đến trang có chữ cái đầu tiên của từ đó và nhanh chóng tìm thấy nó. Dictionary trong Python cũng hoạt động tương tự, nó biết "vị trí" của khóa mà bạn đang tìm kiếm.

Ví dụ:

# Tạo một dictionary lớn (ví dụ)
danh_sach_san_pham = {
    "SP001": {"ten": "Laptop", "gia": 1200},
    "SP002": {"ten": "Điện thoại", "gia": 800},
    "SP003": {"ten": "Máy tính bảng", "gia": 500},
    # ... rất nhiều sản phẩm khác
    "SP999": {"ten": "Bàn phím", "gia": 75}


import time

# Giả sử bạn muốn tìm thông tin của sản phẩm "SP002"
start_time = time.time()
thong_tin_sp002 = danh_sach_san_pham["SP002"]
end_time = time.time()

print(f"Thông tin SP002: {thong_tin_sp002}")
print(f"Thời gian truy cập bằng khóa: {end_time - start_time} giây")

# So sánh với việc tìm kiếm trong List (nếu bạn lưu list các dictionary)
# (Chỉ để minh họa, không phải cách lưu trữ tốt cho trường hợp này)
list_san_pham = [
    {"id": "SP001", "ten": "Laptop", "gia": 1200},
    {"id": "SP002", "ten": "Điện thoại", "gia": 800},
    {"id": "SP003", "ten": "Máy tính bảng", "gia": 500},
    # ...
]

start_time_list = time.time()
found_item = None
for item in list_san_pham:
    if item["id"] == "SP002":
        found_item = item
        break
end_time_list = time.time()

print(f"Thông tin SP002 (tìm trong List): {found_item}")
print(f"Thời gian tìm kiếm trong List: {end_time_list - start_time_list} giây")

# Với dictionary, thời gian truy cập gần như không đổi dù dictionary lớn đến đâu.
# Với list, thời gian tìm kiếm sẽ tăng tuyến tính theo kích thước list.

Thường được dùng để biểu diễn các đối tượng, bản ghi

Trong lập trình, chúng ta thường cần biểu diễn các đối tượng trong thế giới thực (như một người, một chiếc xe, một cuốn sách, một đơn hàng) với các thuộc tính khác nhau. Dictionary là một lựa chọn tuyệt vời để làm điều này, vì mỗi khóa có thể đại diện cho một thuộc tính và giá trị của nó là dữ liệu của thuộc tính đó.

Giải thích: Mỗi đối tượng có nhiều đặc điểm. Dictionary cho phép bạn nhóm tất cả các đặc điểm này lại với nhau dưới một tên duy nhất (tên dictionary) và truy cập từng đặc điểm bằng tên của nó (khóa).

Ví dụ:

# Biểu diễn thông tin một chiếc xe hơi
xe_hoi = {
    "hang_sx": "Toyota",
    "model": "Camry",
    "nam_san_xuat": 2022,
    "mau_sac": "Bạc",
    "so_cho_ngoi": 5,
    "dong_co": { # Một dictionary lồng (nested dictionary) để mô tả chi tiết hơn
        "loai": "Xăng",
        "dung_tich": 2.5,
        "ma_luc": 203
    },
    "tinh_nang": ["camera lùi", "cảm biến đỗ xe", "hệ thống định vị"] # Một list các tính năng
}

print("Thông tin xe hơi:")
print(f"Hãng sản xuất: {xe_hoi['hang_sx']}")
print(f"Model: {xe_hoi['model']}")
print(f"Năm sản xuất: {xe_hoi['nam_san_xuat']}")
print(f"Loại động cơ: {xe_hoi['dong_co']['loai']}") # Truy cập vào dictionary lồng
print(f"Tính năng đầu tiên: {xe_hoi['tinh_nang'][0]}") # Truy cập vào list trong dictionary

# Output:
# Thông tin xe hơi:
# Hãng sản xuất: Toyota
# Model: Camry
# Năm sản xuất: 2022
# Loại động cơ: Xăng
# Tính năng đầu tiên: camera lùi

Trong ví dụ trên, xe_hoi là một bản ghi hoàn chỉnh về một chiếc xe, với các thuộc tính như hãng sản xuất, model, màu sắc, và thậm chí cả các thuộc tính phức tạp hơn như thông tin động cơ (là một dictionary khác) hay danh sách các tính năng (là một list).

Kết bài

Qua các phần trên, chúng ta đã cùng nhau khám phá Dictionary – một trong những kiểu dữ liệu cốt lõi và mạnh mẽ nhất trong Python. Từ khái niệm cơ bản về các cặp khóa-giá trị, cách tạo, truy cập, thêm, sửa, xóa các phần tử, cho đến việc sử dụng các phương thức tiện ích và cách lặp qua chúng, hy vọng bạn đã có cái nhìn toàn diện về Dictionary.

Dictionary không chỉ đơn thuần là một nơi để lưu trữ dữ liệu; nó là một công cụ tổ chức thông tin thông minh, giúp mã của bạn trở nên rõ ràng, dễ đọc và hiệu quả hơn. Khả năng truy cập dữ liệu nhanh chóng bằng khóa, cùng với tính linh hoạt trong việc biểu diễn các đối tượng và bản ghi có cấu trúc, đã biến Dictionary thành một phần không thể thiếu trong mọi dự án Python, từ những script đơn giản đến các ứng dụng phức tạp.

Hãy tiếp tục thực hành và thử nghiệm với Dictionary trong các bài toán của riêng bạn. Bạn sẽ sớm nhận ra sức mạnh và sự tiện lợi mà nó mang lại trong việc xử lý dữ liệu. Chúc bạn thành công trên hành trình học Python!

Bài viết liên quan