Viết mã Python dễ bảo trì thông qua một ví dụ

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
  • Tách các khối code phức tạp: Mỗi hàm chỉ làm một việc:
  • 
    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

    Thẻ: python PEP 8 Exception Handling Code Maintainability HTTP Requests

    Đăng vào ngày 21 tháng 5 lúc 16:37