3 คะแนน โดย GN⁺ 2024-04-28 | 1 ความคิดเห็น | แชร์ทาง WhatsApp

PEP 686 - ตั้งค่าโหมด UTF-8 เป็นค่าเริ่มต้นตั้งแต่ Python 3.15

  • UTF-8 กำลังกลายเป็นมาตรฐานการเข้ารหัสข้อความโดยพฤตินัย
    • การเข้ารหัสเริ่มต้นของไฟล์ซอร์ส Python คือ UTF-8
    • JSON, TOML, YAML ใช้ UTF-8
    • โปรแกรมแก้ไขข้อความส่วนใหญ่ เช่น Visual Studio Code, Windows Notepad ใช้ UTF-8 เป็นค่าเริ่มต้น
    • เว็บไซต์ส่วนใหญ่และข้อมูลข้อความบนอินเทอร์เน็ตใช้ UTF-8
    • ภาษาโปรแกรมยอดนิยมอื่น ๆ จำนวนมาก เช่น Node.js, Go, Rust, Java ก็ใช้ UTF-8 เป็นค่าเริ่มต้นเช่นกัน
  • การเปลี่ยนการเข้ารหัสเริ่มต้นเป็น UTF-8 จะทำให้ Python ทำงานร่วมกับภาษาอื่นได้ง่ายขึ้น
  • นักพัฒนา Python จำนวนมากที่ใช้ Unix มักลืมไปว่าการเข้ารหัสเริ่มต้นแตกต่างกันไปตามแพลตฟอร์ม
    • เมื่อต้องอ่านไฟล์ข้อความที่เข้ารหัสด้วย UTF-8 (เช่น JSON, TOML, Markdown, ไฟล์ซอร์ส Python) มักไม่ระบุ encoding="utf-8"
    • การเข้ารหัสเริ่มต้นที่ไม่สอดคล้องกันทำให้เกิดบั๊กจำนวนมาก

การเปลี่ยนแปลงสำคัญใน PEP 686

  • ตั้งแต่ Python 3.15 เป็นต้นไป โหมด UTF-8 จะถูกเปิดใช้งานเป็นค่าเริ่มต้น
    • ผู้ใช้ยังคงสามารถปิดโหมด UTF-8 ได้ด้วยการตั้งค่า PYTHONUTF8=0 หรือ -X utf8=0
  • เพิ่ม locale.getencoding()
    • เป็น API สำหรับรับการเข้ารหัสตาม locale โดยไม่ขึ้นกับโหมด UTF-8
    • หากระบุออปชัน warn_default_encoding แล้ว locale.getpreferredencoding() จะส่ง EncodingWarning เช่นเดียวกับ open() (ดู PEP 597)
  • ปรับแก้ออปชัน encoding="locale"
    • TextIOWrapper ควรใช้การเข้ารหัสตาม locale แม้อยู่ในโหมด UTF-8 หากระบุ encoding="locale"

ความเข้ากันได้ย้อนหลัง

  • ระบบ Unix ส่วนใหญ่ใช้ locale แบบ UTF-8 และ Python จะเปิดโหมด UTF-8 เมื่อ locale เป็น C หรือ POSIX ดังนั้นการเปลี่ยนแปลงนี้จึงส่งผลหลักกับผู้ใช้ Windows
  • หากโปรแกรม Python พึ่งพาการเข้ารหัสเริ่มต้น การเปลี่ยนแปลงนี้อาจทำให้เกิด UnicodeError, ข้อความเพี้ยน หรือข้อมูลเสียหายแบบเงียบ ๆ ได้
  • แนวทางในการแก้ปัญหาความเข้ากันได้ย้อนหลัง:
    1. ปิดโหมด UTF-8
    2. ใช้ EncodingWarning (PEP 597) เพื่อค้นหาทุกจุดที่ได้รับผลกระทบจากโหมด UTF-8
      • หากละเว้นออปชัน encoding ให้พิจารณาใช้ encoding="utf-8" หรือ encoding="locale"
      • หากมีการใช้ locale.getpreferredencoding() ให้พิจารณาใช้ "utf-8" หรือ locale.getencoding()
    3. ทดสอบแอปพลิเคชันด้วยโหมด UTF-8

ความเห็นของ GN⁺

  • PEP นี้มีเป้าหมายเพื่อทำให้การเข้ารหัสเริ่มต้นของ Python เป็น UTF-8 แบบ统一 เพื่อเพิ่มความสามารถในการทำงานร่วมกับภาษาและระบบอื่น ๆ ซึ่งจะช่วยให้ Python ถูกใช้งานได้ราบรื่นยิ่งขึ้นในสภาพแวดล้อมการพัฒนาระดับโลก
  • อย่างไรก็ตาม การเปลี่ยนแปลงนี้อาจส่งผลต่อความเข้ากันได้ย้อนหลังของโปรแกรม Python ที่มีอยู่เดิม โดยเฉพาะโปรแกรมที่ทำงานในสภาพแวดล้อม Windows ซึ่งต้องใช้ความระมัดระวัง
  • นักพัฒนาควรใช้ EncodingWarning เพื่อระบุส่วนที่ได้รับผลกระทบ และรับมือด้วยวิธีต่าง ๆ เช่น การระบุออปชัน encoding อย่างชัดเจน
  • ในระยะยาว คาดว่าการเปลี่ยนแปลงนี้จะส่งผลเชิงบวกต่อระบบนิเวศของ Python แต่ในระยะสั้น บางโปรเจกต์อาจมีต้นทุนในการย้ายระบบ
  • นักพัฒนาควรคำนึงถึงการเปลี่ยนแปลงนี้เมื่อวางแผนอัปเกรดไปยัง Python 3.15 และหากจำเป็นก็ควรดำเนินมาตรการที่เหมาะสมเพื่อรองรับความเข้ากันได้ย้อนหลัง

1 ความคิดเห็น

 
GN⁺ 2024-04-28
ความคิดเห็นจาก Hacker News
  • การที่ค่าเริ่มต้นของการเข้ารหัสไฟล์ข้อความใน Python แตกต่างกันไปตามแพลตฟอร์มเป็นปัญหามานานแล้ว
  • ปัญหาเรื่องการเข้ารหัสของระบบไฟล์เป็นอีกประเด็นหนึ่ง และการเปลี่ยนแปลงครั้งนี้ไม่ได้จัดการส่วนนั้น
  • การพึ่งพาค่าเริ่มต้นของระบบไม่ใช่เรื่องที่ดี เพราะมันอาจต่างจากที่คาดไว้
  • ในอดีตเคยมีปัญหากับ Ubuntu และสคริปต์ init.d โดยสคริปต์รัน Java ที่ทำงานด้วยสิทธิ์ root ใช้การเข้ารหัสต่างจากผู้ใช้ทั่วไปจนเกิดปัญหา
  • ทุกวันนี้ปัญหาน้อยลงแล้ว แต่ก็ควรหลีกเลี่ยงการปล่อยให้ OS จัดการเรื่องนี้เอง การใช้การเข้ารหัสอื่นที่ไม่ใช่ UTF-8 มีแนวโน้มว่าจะเป็นสิ่งที่ไม่ได้ตั้งใจ
  • การไม่ระบุให้ชัดเจนแล้วไปพึ่งการตั้งค่าของ OS ไม่ใช่เรื่องที่ดี
  • การเปลี่ยนแปลงครั้งนี้เป็นไปในทิศทางที่ดี ถ้ามีโค้ดพังก็ควรแก้ให้เรียบง่าย
  • ดีกว่าปล่อยไว้ในสภาพที่มีโอกาสเกิดบั๊กข้อมูลเสียหาย

กฎจากประสบการณ์ที่ยิ่งเป็นจริงขึ้นเรื่อย ๆ ตลอดหลายทศวรรษที่ผ่านมา: ถ้าการตั้งค่า "charset" ไม่ใช่ UTF-8 แปลว่ามันผิด

  • Python 2 ไม่ยึดติดกับ charset จึงมักทำงานได้เสมอ แต่การปรับปรุงของ Python 3 นั้นเกินกว่าจะเรียกว่าแค่การปรับปรุง

  • วิธีแยกสคริปต์ Python 3 ออกจากสคริปต์ Python 2:

    • ถ้ามีสตริง "utf-8" ก็เป็น Python 3
    • ถ้ารันได้เฉพาะบน locale C.UTF-8 ก็เป็น Python 3
  • การเปลี่ยนแปลงครั้งนี้น่ายินดีต้อนรับ และดูเหมือนจะทำให้ Python 3 "ดีขึ้น"

  • นึกว่ามันเป็นค่าเริ่มต้นมาตั้งแต่ Python 3 แล้ว

ภาษายอดนิยมจำนวนมาก รวมถึง Node.js, Go, Rust และ Java ใช้ UTF-8 เป็นค่าเริ่มต้น

  • ไม่เคยรู้ว่า Java ย้ายจาก UTF-16 มาเป็น UTF-8 แล้ว

  • ไม่แน่ใจว่าการเข้ารหัสภายในของ CPython เป็น UTF-8 หรือไม่

  • สตริงของ Python สามารถทำ indexing ได้ แต่การเข้าถึงแบบสุ่มเกิดขึ้นไม่บ่อย จึงน่าจะดีกว่าถ้าทำดัชนีแบบหน่วงเวลาเมื่อจำเป็น

  • ถ้าแค่เลื่อนไปข้างหน้าหรือถอยหลังทีละตำแหน่งก็ไม่จำเป็นต้องมีดัชนี

  • ดังนั้นจึงดูเหมือนว่าน่าจะใช้ตัวแทนภายในแบบ UTF-8 ได้

  • ทำไมไม่ใช้ utf-8-sig? มันมีประโยชน์เพราะจัดการ BOM แบบเลือกได้

  • พูดถึง UTF-8 แล้ว Linux framebuffer ควรมีการรองรับ UTF-8 ที่เหมาะสมมาตั้งนานแล้ว

  • GNU Hurd มี 'terminal console' ที่ดีกว่าและรองรับ UTF-8 มาตั้งแต่ราวปี 2007

  • นี่ปี 2024 แล้วเพิ่งมีการเปลี่ยนแปลงแบบนี้

  • เป็นการเปลี่ยนแปลงที่ดี ตอนนี้ก็เหลือแค่ JS ที่ต้องเปลี่ยนมาใช้ UTF-8 แต่การปรับปรุงทำได้ยากเพราะต้องเข้ากันได้กับโค้ดที่เขียนไว้ตั้งแต่ปี 1995

นักพัฒนา Python บน Unix จำนวนมากลืมไปว่าการเข้ารหัสเริ่มต้นแตกต่างกันไปตามแพลตฟอร์ม และไม่ระบุ encoding="utf-8" เมื่ออ่านไฟล์ข้อความ UTF-8

  • จะว่า "ลืม" ก็คงไม่เชิง ดูเหมือนจะเป็นการไม่ตระหนักอย่างถูกต้องมากกว่า
  • ผมคิดมาตลอดว่า ถ้าไม่ได้ขออย่างชัดเจน Python จะใช้ UTF-8 ทุกที่อยู่แล้ว