3 điểm bởi GN⁺ 2024-04-28 | 1 bình luận | Chia sẻ qua WhatsApp

PEP 686 - Từ Python 3.15, chế độ UTF-8 được đặt làm mặc định

  • UTF-8 đang dần trở thành chuẩn mã hóa văn bản trên thực tế
    • Mã hóa mặc định của tệp nguồn Python là UTF-8
    • JSON, TOML, YAML sử dụng UTF-8
    • Hầu hết trình soạn thảo văn bản như Visual Studio Code, Windows Notepad đều dùng UTF-8 theo mặc định
    • Phần lớn website và dữ liệu văn bản trên Internet sử dụng UTF-8
    • Nhiều ngôn ngữ lập trình phổ biến khác như Node.js, Go, Rust, Java cũng dùng UTF-8 theo mặc định
  • Việc chuyển mã hóa mặc định sang UTF-8 giúp Python dễ tương tác hơn với các ngôn ngữ khác
  • Nhiều nhà phát triển Python trên Unix quên mất rằng mã hóa mặc định khác nhau tùy theo nền tảng
    • Khi đọc các tệp văn bản được mã hóa bằng UTF-8 (JSON, TOML, Markdown, tệp nguồn Python, v.v.), họ không chỉ định encoding="utf-8"
    • Nhiều lỗi phát sinh do mã hóa mặc định không nhất quán

Những thay đổi chính của PEP 686

  • Từ Python 3.15, chế độ UTF-8 sẽ được bật mặc định
    • Người dùng vẫn có thể tắt chế độ UTF-8 bằng cách đặt PYTHONUTF8=0 hoặc -X utf8=0
  • Thêm locale.getencoding()
    • API để lấy mã hóa locale bất kể chế độ UTF-8
    • Nếu tùy chọn warn_default_encoding được chỉ định, locale.getpreferredencoding() sẽ phát sinh EncodingWarning giống như open() (tham khảo PEP 597)
  • Điều chỉnh tùy chọn encoding="locale"
    • TextIOWrapper phải sử dụng mã hóa locale ngay cả trong chế độ UTF-8 nếu encoding="locale" được chỉ định

Tính tương thích ngược

  • Hầu hết hệ thống Unix sử dụng locale UTF-8, và Python bật chế độ UTF-8 khi locale là C hoặc POSIX, vì vậy thay đổi này chủ yếu ảnh hưởng đến người dùng Windows
  • Nếu chương trình Python phụ thuộc vào mã hóa mặc định, thay đổi này có thể gây ra UnicodeError, lỗi hiển thị ký tự, hoặc hỏng dữ liệu âm thầm
  • Hướng dẫn để xử lý các vấn đề tương thích ngược:
    1. Tắt chế độ UTF-8
    2. Dùng EncodingWarning (PEP 597) để tìm mọi vị trí bị ảnh hưởng bởi chế độ UTF-8
      • Nếu bỏ qua tùy chọn encoding, hãy cân nhắc dùng encoding="utf-8" hoặc encoding="locale"
      • Nếu đang dùng locale.getpreferredencoding(), hãy cân nhắc dùng "utf-8" hoặc locale.getencoding()
    3. Kiểm thử ứng dụng với chế độ UTF-8

Ý kiến của GN⁺

  • PEP này nhằm thống nhất mã hóa mặc định của Python về UTF-8 để tăng khả năng tương tác với các ngôn ngữ và hệ thống khác. Điều này sẽ giúp Python được sử dụng trơn tru hơn trong môi trường phát triển toàn cầu
  • Tuy nhiên, thay đổi này có thể ảnh hưởng đến tính tương thích ngược của các chương trình Python hiện có. Đặc biệt, cần chú ý với các chương trình chạy trong môi trường Windows
  • Các nhà phát triển nên tận dụng EncodingWarning để xác định những phần bị ảnh hưởng, và ứng phó bằng cách chỉ định rõ ràng tùy chọn encoding
  • Về dài hạn, thay đổi này được kỳ vọng sẽ mang lại tác động tích cực cho hệ sinh thái Python. Tuy nhiên, trong ngắn hạn, một số dự án có thể phát sinh chi phí di chuyển
  • Các nhà phát triển nên cân nhắc thay đổi này khi lập kế hoạch nâng cấp lên Python 3.15, và nếu cần thì áp dụng các biện pháp phù hợp để đảm bảo tương thích ngược

1 bình luận

 
GN⁺ 2024-04-28
Ý kiến trên Hacker News
  • Việc mã hóa mặc định cho tệp văn bản của Python khác nhau tùy nền tảng từ lâu đã là một vấn đề
  • Vấn đề mã hóa hệ thống tệp là chuyện khác và không được đề cập trong thay đổi lần này
  • Phụ thuộc vào giá trị mặc định của hệ thống là không tốt, vì nó có thể khác với giả định
  • Trước đây đã từng có vấn đề với Ubuntu và các script init.d. Các script khởi chạy Java chạy bằng quyền root đã dùng mã hóa khác với người dùng thông thường, gây ra sự cố
  • Ngày nay vấn đề này ít gặp hơn, nhưng vẫn nên tránh giao việc này cho OS. Việc dùng mã hóa khác UTF-8 nhiều khả năng là ngoài ý muốn
  • Không chỉ định rõ ràng mà phụ thuộc vào thiết lập của OS là không tốt
  • Thay đổi lần này là đi đúng hướng. Mã bị lỗi thì nên sửa đơn giản còn hơn
  • Như vậy vẫn tốt hơn là để nguyên trong trạng thái có thể phát sinh lỗi làm hỏng dữ liệu

Kinh nghiệm thực tế ngày càng đúng hơn trong vài thập kỷ gần đây: nếu thiết lập "charset" không phải UTF-8 thì tức là nó sai

  • Python 2 không bị ràng buộc bởi charset nên lúc nào cũng chạy ổn, nhưng các cải tiến của Python 3 còn hơn cả cải tiến đơn thuần

  • Cách phân biệt script Python 3 với script Python 2:

    • Có chuỗi "utf-8" thì là Python 3
    • Chỉ chạy được trong locale C.UTF-8 thì là Python 3
  • Thay đổi này rất đáng hoan nghênh và có vẻ sẽ "cải thiện" Python 3

  • Tôi đã nghĩ đây là mặc định từ Python 3 rồi

Nhiều ngôn ngữ phổ biến, bao gồm Node.js, Go, Rust và Java, mặc định sử dụng UTF-8

  • Tôi không biết là Java đã chuyển từ UTF-16 sang UTF-8

  • Tôi không rõ mã hóa nội bộ của CPython có phải là UTF-8 hay không

  • Chuỗi trong Python có thể được đánh chỉ mục, nhưng truy cập ngẫu nhiên là hiếm, nên có lẽ tốt hơn là lập chỉ mục trì hoãn khi cần

  • Nếu chỉ di chuyển tới lui từng ký tự một thì không cần chỉ mục

  • Vì vậy có vẻ nội bộ hoàn toàn có thể biểu diễn bằng UTF-8

  • Tại sao không phải là utf-8-sig? Nó hữu ích vì có thể xử lý BOM một cách tùy chọn

  • Nói về UTF-8, Linux framebuffer lẽ ra từ lâu đã phải có hỗ trợ UTF-8 đúng nghĩa

  • GNU Hurd đã có một 'terminal console' tốt hơn hỗ trợ UTF-8 từ khoảng năm 2007

  • Mãi đến năm 2024 mới có thay đổi kiểu này

  • Thay đổi tốt. Giờ chỉ còn JS là cần chuyển sang UTF-8, nhưng vì phải tương thích với mã viết từ năm 1995 nên rất khó cải thiện

Nhiều nhà phát triển Python trên Unix quên mất rằng mã hóa mặc định khác nhau giữa các nền tảng, và khi đọc tệp văn bản UTF-8 thì không ghi rõ encoding="utf-8"

  • Có lẽ không phải là "quên", mà là họ không thực sự nhận thức được điều đó
  • Tôi đã nghĩ rằng Python sẽ chỉ dùng UTF-8 ở mọi nơi trừ khi có yêu cầu rõ ràng khác đi