Chúng ta cùng tìm hiểu cách viết mã Python dễ bảo trì thông qua một ví dụ cụ thể.
Ví dụ từ trường hợp thực tế
import json
import urllib.request
def get(endpoint, student):
result = None
try:
info1 = urllib.request.urlopen(f"{endpoint}/student/{student}/")
if info1.status_code == 200:
result1 = json.loads(info1.read())
info1.close()
result2 = urllib.request.urlopen(f"{endpoint}/class/{result1['class']}/")
if result2.status_code == 200:
info2 = json.loads(result2.read())
result = info2["name"]
result2.close()
else:
result2.close()
else:
info1.close()
except Exception as e:
return "unknown"
return result
Code trên đây có một số vấn đề cần cải thiện:
Quy tắc đặt tên biến
- Tên biến phải có ý nghĩa rõ ràng: Tránh sử dụng các từ rộng như "day", "host", "cards", "temp". Thay vào đó, nên sử dụng các tên như "day_of_week", "host_to_reboot", "expired_cards".
- Consistency: Đảm bảo các biến cùng loại có tên gọi nhất quán. Ví dụ:
def fetch_image():
return ""
photo = fetch_image()
image = fetch_image()
Nếu photo và image cùng giá trị, cần đặt tên cho chúng rõ ràng.
- Loại dữ liệu: Cố gắng sử dụng các tên biến cho thấy rõ loại dữ liệu. Ví dụ:
student_id = 123
class_name = "A1"
Code đã được cải thiện:
def get_class_name_by_student_id(endpoint: str, student_id: int) -> str:
class_name = ""
try:
student_response = urllib.request.urlopen(f"{endpoint}/student/{student_id}/")
if student_response.status_code != 200:
student_response.close()
return "unknown"
student_info = json.loads(student_response.read())
student_response.close()
class_response = urllib.request.urlopen(f"{endpoint}/class/{student_info['class']}/")
if class_response.status_code != 200:
class_response.close()
return "unknown"
class_info = json.loads(class_response.read())
class_name = class_info["name"]
class_response.close()
except Exception as e:
return "unknown"
return class_name
Optimize các cấu trúc điều kiện
Tránh các cấu trúc điều kiện lồng nhau phức tạp:
if condition1:
if condition2:
if condition3:
# code
Cải thiện bằng cách:
- Trả về sớm: Kiểm tra điều kiện và trả về ngay khi không thỏa mãn:
def process_data(data):
if not condition1:
return None
if not condition2:
return None
if not condition3:
return None
# code
def process_item(item):
if condition2:
# code
else:
# code khác
def process_data(data):
for item in data:
if condition1:
process_item(item)
else:
# code khác
Tránh code trùng lặp
Code trên có một số phần trùng lặp:
student_response.close()
class_response.close()
Cải thiện bằng cách sử dụng context manager:
def get_class_name_by_student_id(endpoint: str, student_id: int) -> str:
try:
with urllib.request.urlopen(f"{endpoint}/student/{student_id}/") as student_response:
if student_response.status_code != 200:
return "unknown"
student_info = json.loads(student_response.read())
with urllib.request.urlopen(f"{endpoint}/class/{student_info['class']}/") as class_response:
class_info = json.loads(class_response.read())
return class_info.get("name", "unknown")
except Exception as e:
return "unknown"
Xử lý ngoại lệ hiệu quả
- Không bắt ngoại lệ chung: Chỉ bắt các ngoại lệ cụ thể có thể xảy ra.
- Log thông báo: Ghi lại thông báo lỗi để dễ dàng debug.
import requests
from loguru import logger
def get_class_name_by_student_id(endpoint: str, student_id: int) -> str:
try:
student_info = requests.get(f"{endpoint}/student/{student_id}/").json()
except requests.exceptions.RequestException as e:
logger.warning(f"Lỗi khi lấy thông tin sinh viên: {str(e)}")
return "unknown"
try:
class_info = requests.get(f"{endpoint}/class/{student_info['class']}/").json()
return class_info.get("name", "unknown")
except requests.exceptions.RequestException as e:
logger.warning(f"Lỗi khi lấy thông tin lớp học: {str(e)}")
return "unknown"
Các công cụ hỗ trợ
Dùng các công cụ như:
- Black: Định dạng code全自动
- YAPF: Định dạng code theo PEP 8
- autopep8: Kiểm tra và sửa code theo PEP 8
- pylint: Kiểm tra code chất lượng
- isort: Sắp xếp các import
Điểm chính
- Thực hiện các hướng dẫn PEP 8
- Giảm thiểu các cấu trúc if lồng nhau
- Tránh code trùng lặp, sử dụng các hàm riêng
- Xử lý ngoại lệ cụ thể
- Thử các thư viện bên thứ ba như requests để code ngắn gọn hơn