C10-07 · Tìm lỗi: bản đọc lệnh
Xem dạng PDFĐề
Bài tìm lỗi của Chương 10. Chương trình dưới đây định làm đúng việc của bản đọc lệnh ở mục 10.3.4: đọc danh sách ban đầu gồm n sinh viên theo khung XS-07 (dòng mã sai bị bỏ qua lặng lẽ), rồi thực hiện m lệnh bằng quan_ly.chay_lenh, in kết quả của từng lệnh. Nhưng với ví dụ của mục 10.3.4 (Ví dụ 1 bên dưới), nó in 23010001 KHONG TIM THAY ở lệnh cuối; còn với n = 0 (Ví dụ 2) thì bị Runtime Error.
import quan_ly
for _ in range(int(input())):
ds_sv = []
sv = quan_ly.tao_sinh_vien(input())
if sv is not None:
ds_sv.append(sv)
for _ in range(int(input())):
lenh = input().split()
print("\n".join(quan_ly.chay_lenh(ds_sv, lenh)))
Hãy chỉ ra dòng gây ra cả hai lỗi, giải thích vì sao, sửa rồi nộp. Bài nộp phải in đúng như chương trình đúng của mục 10.3.4 (dùng quan_ly.py không sửa) với mọi dữ liệu thỏa ràng buộc.
Các lệnh (bảng của mục 10.1, bản đọc lệnh):
| Lệnh | Kết quả in |
|---|---|
XEM |
mỗi sinh viên một dòng ma Ho Ten diem_hp loai theo thứ tự trong danh sách; rỗng: RONG |
THEM ma ho ten qt ck |
ma DA THEM; mã sai: ma MA SAI; thiếu điểm, điểm là chữ, tên có dấu phẩy: LENH SAI; mã đã có: ma TRUNG |
TIM ma |
dòng của sinh viên đó, hoặc ma KHONG TIM THAY |
SUA ma qt ck / XOA ma |
ma DA SUA / ma DA XOA, hoặc ma KHONG TIM THAY |
THONGKE |
năm dòng A so, …, F so |
| lệnh lạ, thiếu tham số, dòng trống | LENH SAI |
Dữ liệu vào
- Dòng đầu: số nguyên n; n dòng tiếp theo, mỗi dòng
ma ho ten diem_qt diem_ck(như C10-01). - Dòng tiếp: số nguyên m; m dòng tiếp theo, mỗi dòng một lệnh.
Kết quả
Với mỗi lệnh, theo thứ tự, các dòng kết quả như bảng trên.
Ràng buộc
- 0 ≤ n ≤ 1000; 0 ≤ m ≤ 1000.
- Mã sinh viên trong danh sách: 1–12 ký tự, chỉ gồm chữ số và chữ cái Latin; hợp lệ khi gồm đúng 8 chữ số. Các mã hợp lệ của danh sách ban đầu không trùng nhau.
- Họ tên trong danh sách: 1–10 từ, mỗi từ 1–20 chữ cái Latin không dấu, hoa thường tùy ý; giữa các phần có thể có nhiều dấu cách.
- Mỗi điểm trong danh sách thuộc [0; 10], dạng số nguyên hoặc một chữ số thập phân, dấu chấm hoặc dấu phẩy.
- Mỗi dòng lệnh có thể trống; nếu không, gồm tối đa 14 phần cách nhau bởi dấu cách, mỗi phần 1–20 ký tự là chữ cái Latin, chữ số, dấu chấm, dấu phẩy hoặc dấu trừ. Tên lệnh là một trong sáu lệnh trên hoặc một từ lạ (không có
TOP,TENcủa C10-06). XEM,THONGKEkhông có tham số;TIM,XOAnhiều nhất 1 tham số;SUAnhiều nhất 3 tham số.- Ở vị trí điểm của
THEM,SUA: phần có chữ số luôn là số trong [0; 10] có tối đa 1 chữ số thập phân (SUAchỉ dùng dấu chấm); phần không có chữ số chỉ gồm chữ cái (không cónan,inf). Vì vậy các "chỗ hở" mà mục 10.4 nêu (điểm 11,SUA … 4,5) không xuất hiện ở bài này.
Gợi ý
Thử tay với n = 2: sau lượt đầu ds_sv có mấy người, sau lượt hai còn mấy? Với n = 0, thân vòng lặp chạy mấy lần, và tên ds_sv đã được gán lần nào chưa khi vòng lệnh dùng tới nó? Nộp một tệp: chép các hàm của quan_ly.py (phụ lục) lên đầu, bỏ import quan_ly và tiền tố quan_ly.. Đừng sửa quan_ly.py: lỗi không nằm ở đó.
Ví dụ 1
Dữ liệu vào:
2
23010001 Nguyen Van An 7.5 8.0
2301002 Tran Thi Binh 6.5 7.0
3
THEM 23010003 le minh DUC 8,0 8.8
TIM 23010003
XOA 23010001
Kết quả:
23010003 DA THEM
23010003 Le Minh Duc 8.5 A
23010001 DA XOA
Ví dụ 2
Dữ liệu vào:
0
1
XEM
Kết quả:
RONG
Giải thích ví dụ
- Ví dụ 1 (ví dụ của mục 10.3.4): An hợp lệ; dòng
2301002 …có mã 7 chữ số nên bị bỏ qua — danh sách ban đầu chỉ có An.THEMthêm Duc (họ tên chuẩn hóa, 0,4 × 8 + 0,6 × 8,8 = 8,48 → 8,5 A),TIMthấy Duc,XOA 23010001xóa An:23010001 DA XOA. Bản lỗi lại in23010001 KHONG TIM THAY, nghĩa là tới lúc xóa, An đã không còn trongds_sv— hãy lần xem An mất ở bước nào. - Ví dụ 2: danh sách ban đầu rỗng nên
XEMinRONG. Bản lỗi dừng với Runtime Error; đọc kỹ tên lỗi và dòng mà Python chỉ ra (Phụ lục C của sách) để biết tên nào chưa từng được gán. - Hai lỗi có chung một nguyên nhân và sửa được bằng cách sửa đúng một chỗ.
Phụ lục: các hàm của quan_ly.py (mục 10.3)
Chép nguyên từ sách (bỏ ba hàm đọc/ghi tệp CSV tach_dong_csv, ghi_danh_sach, doc_danh_sach vì bài nộp không dùng tệp). Hệ thống chấm chỉ nhận một tệp: chép các hàm này lên đầu bài nộp, bỏ dòng import quan_ly và bỏ tiền tố quan_ly. trước tên hàm.
def tinh_diem_hp(diem_qt, diem_ck):
return round(0.4 * diem_qt + 0.6 * diem_ck, 1)
def xep_loai(diem_hp):
if diem_hp >= 8.5:
return "A"
if diem_hp >= 7.0:
return "B"
if diem_hp >= 5.5:
return "C"
if diem_hp >= 4.0:
return "D"
return "F"
def chuan_hoa_ho_ten(ho_ten):
return " ".join(ho_ten.split()).title()
def ma_sv_hop_le(ma):
return len(ma) == 8 and ma.isdigit()
def tach_dong(dong):
ma, phan_sau = dong.split(maxsplit=1)
if not ma_sv_hop_le(ma):
return None
ho_ten, diem_qt, diem_ck = phan_sau.rsplit(maxsplit=2)
diem_qt = float(diem_qt.replace(",", "."))
diem_ck = float(diem_ck.replace(",", "."))
return (ma, chuan_hoa_ho_ten(ho_ten), diem_qt, diem_ck)
def tao_sinh_vien(dong):
ban_ghi = tach_dong(dong)
if ban_ghi is None:
return None
ma, ho_ten, diem_qt, diem_ck = ban_ghi
return {"ma": ma, "ho_ten": ho_ten, "diem_qt": diem_qt, "diem_ck": diem_ck}
def tim_theo_ma(ds_sv, ma):
for sv in ds_sv:
if sv["ma"] == ma:
return sv
return None
def them_sv(ds_sv, dong):
ma = dong.split()[0]
sv = tao_sinh_vien(dong)
if sv is None:
return ma + " MA SAI"
if "," in sv["ho_ten"]:
return "LENH SAI"
if tim_theo_ma(ds_sv, ma) is not None:
return ma + " TRUNG"
ds_sv.append(sv)
return ma + " DA THEM"
def sua_diem(ds_sv, ma, diem_qt, diem_ck):
sv = tim_theo_ma(ds_sv, ma)
if sv is None:
return ma + " KHONG TIM THAY"
sv["diem_qt"], sv["diem_ck"] = diem_qt, diem_ck
return ma + " DA SUA"
def xoa_sv(ds_sv, ma):
sv = tim_theo_ma(ds_sv, ma)
if sv is None:
return ma + " KHONG TIM THAY"
ds_sv.remove(sv)
return ma + " DA XOA"
def dong_bang_diem(sv):
diem_hp = tinh_diem_hp(sv["diem_qt"], sv["diem_ck"])
return " ".join([sv["ma"], sv["ho_ten"],
f"{diem_hp:.1f}", xep_loai(diem_hp)])
def bang_diem(ds_sv):
if len(ds_sv) == 0:
return ["RONG"]
return [dong_bang_diem(sv) for sv in ds_sv]
def dem_theo_loai(ds_sv):
dem = {}
for sv in ds_sv:
diem_hp = tinh_diem_hp(sv["diem_qt"], sv["diem_ck"])
loai = xep_loai(diem_hp)
dem[loai] = dem.get(loai, 0) + 1
return dem
def thong_ke(ds_sv):
dem = dem_theo_loai(ds_sv)
return [loai + " " + str(dem.get(loai, 0))
for loai in "ABCDF"]
def thuc_hien(ds_sv, lenh):
if lenh[0] == "XEM":
return bang_diem(ds_sv)
if lenh[0] == "THONGKE":
return thong_ke(ds_sv)
if lenh[0] == "TIM":
sv = tim_theo_ma(ds_sv, lenh[1])
if sv is None:
return [lenh[1] + " KHONG TIM THAY"]
return [dong_bang_diem(sv)]
if lenh[0] == "THEM":
return [them_sv(ds_sv, " ".join(lenh[1:]))]
if lenh[0] == "SUA":
return [sua_diem(ds_sv, lenh[1],
float(lenh[2]), float(lenh[3]))]
if lenh[0] == "XOA":
return [xoa_sv(ds_sv, lenh[1])]
return ["LENH SAI"]
def chay_lenh(ds_sv, lenh):
try:
return thuc_hien(ds_sv, lenh)
except (ValueError, IndexError):
return ["LENH SAI"]
Nguồn trong sách: Bài C10-07, mục 10.5, giáo trình Lập trình cơ sở với Python — TS. Nguyễn Quốc Long · Mức: (**)