Học bằng cách đọc theo thứ tự

json và csv — I/O cho dữ liệu có cấu trúc

Học chuyển đổi hai chiều với json.dumps/loadsensure_ascii, đọc/ghi theo vị trí với csv.writer/reader, và đọc/ghi theo tên cột với DictWriter/DictReader qua dữ liệu Titanic.

Bài này nói về I/O cho hai định dạng dữ liệu có cấu trúc thường gặp — json, hay được web API dùng, và csv, mở gọn gàng trong phần mềm bảng tính.

JSON vs CSV — Khi nào dùng cái nào?
JSONphổ biến trong web APIcặp khóa/giá trịcho phép lồng nhauCSVphổ biến trong phân tích dữ liệu1 dòng = 1 bản ghimở trong bảng tínhđặc điểmđặc điểm
JSON có thể biểu diễn cặp khóa/giá trị và cấu trúc lồng nhau, nên xuất hiện khắp nơi trong response của web API và file cấu hình. CSVđịnh dạng bảng "1 dòng = 1 bản ghi" phẳng, mở trực tiếp trong bảng tính như Excel, là chủ lực cho phân tích dữ liệu.

json — Chuyển đổi hai chiều giữa object Python và chuỗi JSON

JSON (JavaScript Object Notation) là định dạng văn bản nhẹ biểu diễn cấu trúc chỉ bằng "cặp khóa/giá trị" và "list có thứ tự", được dùng làm tiêu chuẩn cho response web API và file cấu hình. Module json của Python chuyển đổi dict, list, chuỗi, số, bool và None sang và từ JSON.

Chỉ cần nhớ hai hàm cơ bản. json.dumps(object) chuyển Python → chuỗi JSON, và json.loads(string) chuyển chuỗi JSON → Python. Chữ s ở cuối là viết tắt của string — phân biệt với dump / load, vốn làm việc trực tiếp với file.

Tính đối xứng của json.dumps và json.loads
object Pythondict / list / str / numjson.dumpschuỗi JSON{ "name": "Minh" }chuỗi JSON{ "name": "Minh" }json.loadsobject Pythondict / list / str / numghiđọc
Hàng trên: dumps (dump string) = chiều Python → chuỗi JSON. Hàng dưới: loads (load string) = chiều chuỗi JSON → Python. Các biến thể không có s (dump / load) làm việc trực tiếp với đối tượng file.
HàmVai tròGhi chú
json.dumps(obj)Python → chuỗi JSONtrả về str
json.loads(text)chuỗi JSON → Pythontrả về dict / list / v.v.
json.dump(obj, file)Python → ghi vào filetruyền f từ open()
json.load(file)file → Pythontruyền f từ open()
indent=Nin đẹp với thụt lề N spacecho người đọc
ensure_ascii=Falsexuất ký tự non-ASCII nguyên dạngmặc định escape chúng

ensure_ascii mặc định là True

Mặc định, json.dumps({"name": "café"}) xuất '{"name": "caf\u00e9"}'ký tự non-ASCII bị escape thành \u. Về kỹ thuật vẫn hợp lệ, nhưng khó đọc cho người và làm phình kích thước file, nên với dữ liệu chứa ký tự non-ASCII (dấu, emoji, CJK, v.v.), hãy tạo thói quen truyền ensure_ascii=False.

Chuyển thông tin user thành JSON, parse ngược lại thành object Python, và kiểm tra kiểu của từng biến bằng type().

① Hãy import module json.

② Hãy xây dict với name="Minh" và list mặt hàng ["Apple", "Banana"] (hai key: nameitems).

③ Hãy chuyển dict thành chuỗi JSON in đẹp (có thụt lề) rồi in, sau đó in type(text): để hiện kiểu của chuỗi JSON (tắt escape non-ASCII phòng khi dữ liệu chứa dấu, emoji, v.v.).

④ Hãy parse chuỗi JSON ngược lại thành object Python, rồi in type(parsed):type(items): lần lượt (lấy items ra từ parsed).

⑤ Từ object đã parse, hãy in tên: ◯◯Mặt hàng đầu tiên: ◯◯ (phần tử đầu của items).

(Nếu chạy đúng, phần giải thích sẽ hiện ra.)

Python Editor

Chạy code để xem đầu ra

Cơ bản về csv — Xử lý dòng với reader và writer

CSV (Comma-Separated Values) là định dạng văn bản thuần trong đó một dòng phân tách bằng dấu phẩy bằng một bản ghi, và vì phần mềm bảng tính như Excel mở được trực tiếp, nó xuất hiện khắp nơi trong workflow nghiệp vụ. Module csv của Python cung cấp các hàm để đọc và ghi định dạng này theo từng dòng.

Cơ bản gồm csv.writer(file)csv.reader(file): cái trước ghi một list giá trị thành một dòng, cái sau đọc CSV từng dòng một thành một list giá trị. Hai điểm cần lưu ý: thứ nhất, mọi thứ đọc về đều là chuỗi — nếu cần số nguyên, hãy tự chuyển đổi bằng int(). Thứ hai, luôn truyền newline='' cho open(...) để module csv tự quản lý ký tự xuống dòng.

csv.writer và csv.reader làm gì
list giá trị["Minh", 30]csv.writerwriterowvăn bản CSVMinh,30csv.readerfor row in readerlist giá trị['Minh', '30'] (tất cả là str)ghiđọc
writer.writerow(list) ghi một list giá trị thành một dòng CSV. reader làm chiều ngược lại — lấy một dòng CSV ra thành một list giá trị — và quan trọng là mọi giá trị đều ra dạng chuỗi.

Luôn truyền newline='' cho open

Module csv tự quản lý ký tự xuống dòng, nên bạn cần truyền newline='' kiểu open("x.csv", "w", newline=''). Bỏ qua thì có thể dẫn đến CSV chứa dòng trống trên Windows — một lỗi điển hình được tài liệu Python chính thức nhắc đến.

Ghi một list user vào CSV, rồi đọc lại từng dòng dùng file output.csv trên hệ thống file ảo trong trình duyệt (VFS).

① Hãy import module csv.

② Hãy mở output.csvchế độ ghi (với newline=''), tạo writer, và ghi 3 dòng: header ["name", "age"] và hai dòng dữ liệu ["Minh", 30]["Linh", 25].

③ Hãy mở lại file đó ở chế độ đọc (với newline=''), tạo reader, và in từng dòng bằng for row in reader:.

Python Editor

Chạy code để xem đầu ra

DictWriter và DictReader — Đọc và ghi theo tên cột

csv.writer / reader ở phần trước hoạt động theo vị trí, nên thêm cột hoặc đổi thứ tự buộc bạn phải sửa lại mọi truy cập row[0] / row[1]. DictWriter / DictReader là phiên bản đọc và ghi theo tên cột (header) — bạn có thể ghi một list các dict thẳng vào CSV và đọc lại thành một list các dict.

Dữ liệu thực tế phần lớn là CSV có dòng header, nên trong dự án thực tế bạn sẽ dùng các hàm này nhiều hơn hẳn.

Vì sao DictWriter / DictReader tiện lợi
list các dict[{name: ..., age: ...}]DictWriterwriteheader+ writerowsCSV có headername,ageMinh,30DictReaderfor row in readerlist các dicttruy cập row["name"]ghiđọc
DictWriter biến list các dict thành CSV với dòng header được định nghĩa bởi fieldnames. DictReader làm chiều ngược lại — đọc CSV có dòng header thành list các dict, để bạn truy cập giá trị theo tên cột kiểu row["name"].

Ghi một list-of-dicts user vào users.csv, rồi đọc lại và in từng dòng đã định dạng. Thử đọc theo tên cột thay vì theo vị trí.

① Hãy import csv.

② Hãy xây list hai user (3 cột: name / age / city).

- User đầu: name="Minh", age=30, city="Tokyo"

- User sau: name="Linh", age=25, city="Osaka"

③ Hãy mở users.csv ở chế độ ghi, tạo DictWriter, và ghi header + dữ liệu (truyền fieldnames=["name", "age", "city"]).

④ Hãy mở lại file và tạo DictReader, in từng dòng theo dạng {name} ({age} tuổi) {city}.

Python Editor

Chạy code để xem đầu ra

Ví dụ thực tế: Tổng hợp titanic.csv

Đến giờ ta đã tạo các tập dữ liệu nhỏ trong code và ghi chúng ra. Hãy kết thúc bằng việc đọc một tập dữ liệu thực và tổng hợp. Đối tượng là tập dữ liệu Titanic nổi tiếng trên Kaggle (891 dòng / 12 cột), với các cột như PassengerId / Survived (0 = chết, 1 = sống sót) / Pclass (hạng cabin) / Name / Sex / Age / Fare.

python_console của bài thực hành nạp sẵn CSV bên ngoài vào hệ thống file ảo (VFS) trong trình duyệt qua fileUrls, nên code của bạn chỉ cần gọi open("titanic.csv"). Ta sẽ viết cùng một bài tập với cả csv.reader (theo vị trí) và csv.DictReader (theo tên cột).

Dùng csv.reader theo vị trí để đọc titanic.csv và đếm tổng số hành khách và số người sống sót.

① Hãy import module csv.

② Hãy mở titanic.csv ở chế độ đọc (với newline='') và tạo reader.

③ Hãy bỏ qua dòng header bằng next(reader).

④ Hãy lặp phần còn lại với for row in reader: và đếm totalsurvived (các dòng có cột Survived = index 1 là "1").

⑤ Hãy in Tổng: 891Sống sót: 342.

Python Editor

Chạy code để xem đầu ra

Dùng csv.DictReader theo tên cột để đọc titanic.csv và tính trung bình của cột Age. Dữ liệu Titanic có dòng mà Age bị trống, nên ta cũng xử lý điều đó.

① Hãy import csv.

② Hãy mở titanic.csv ở chế độ đọc (với newline='') và tạo DictReader.

③ Trong vòng lặp, lấy row["Age"] của từng dòng và gom chỉ những dòng không rỗng dưới dạng float(row["Age"]) vào một list.

④ Hãy in số dòng hợp lệtuổi trung bình (2 chữ số thập phân) như sau:

- Bản ghi hợp lệ: ◯ (kỳ vọng: 714)

- Tuổi trung bình: ◯◯.◯◯ (kỳ vọng: 29.70)

Python Editor

Chạy code để xem đầu ra
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1json.dumps({"name": "café"}, ensure_ascii=False) cho ra kết quả nào?

Câu 2Kiểu của giá trị trả về khi đọc dòng bằng csv.reader là gì?

Câu 3Cái nào hợp nhất để đọc một CSV có dòng header thành list các dict?