3P by neo 18일전 | favorite | 댓글 1개

PEP 686 - Python 3.15부터 UTF-8 모드를 기본값으로 설정

  • UTF-8이 사실상 표준 텍스트 인코딩이 되어감
    • Python 소스 파일의 기본 인코딩은 UTF-8
    • JSON, TOML, YAML은 UTF-8 사용
    • Visual Studio Code, Windows 메모장 등 대부분의 텍스트 편집기는 기본적으로 UTF-8 사용
    • 대부분의 웹사이트와 인터넷 상의 텍스트 데이터는 UTF-8 사용
    • Node.js, Go, Rust, Java 등 많은 다른 인기 프로그래밍 언어도 기본적으로 UTF-8 사용
  • 기본 인코딩을 UTF-8로 변경하면 Python이 다른 언어와 상호 운용하기가 더 쉬워짐
  • 많은 Unix 사용 Python 개발자들은 기본 인코딩이 플랫폼에 따라 다르다는 사실을 잊어버림
    • UTF-8로 인코딩된 텍스트 파일(JSON, TOML, Markdown, Python 소스 파일 등)을 읽을 때 encoding="utf-8"을 지정하지 않음
    • 일관되지 않은 기본 인코딩으로 인해 많은 버그가 발생함

PEP 686의 주요 변경 사항

  • Python 3.15부터 UTF-8 모드가 기본적으로 활성화됨
    • 사용자는 여전히 PYTHONUTF8=0 또는 -X utf8=0을 설정하여 UTF-8 모드를 비활성화할 수 있음
  • locale.getencoding() 추가
    • UTF-8 모드에 관계없이 로케일 인코딩을 얻기 위한 API
    • warn_default_encoding 옵션이 지정되면 locale.getpreferredencoding()open()과 마찬가지로 EncodingWarning을 발생시킴 (PEP 597 참조)
  • encoding="locale" 옵션 수정
    • TextIOWrapperencoding="locale"이 지정된 경우 UTF-8 모드에서도 로케일 인코딩을 사용해야 함

하위 호환성

  • 대부분의 Unix 시스템은 UTF-8 로케일을 사용하고 Python은 로케일이 C 또는 POSIX일 때 UTF-8 모드를 활성화하므로 이 변경은 주로 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로의 업그레이드를 계획할 때 이 변경 사항을 고려해야 하며, 필요한 경우 하위 호환성을 위한 적절한 조치를 취해야 함
Hacker News 의견
  • Python의 기본 텍스트 파일 인코딩이 플랫폼에 따라 다른 것은 오랫동안 문제였음
  • 파일 시스템 인코딩 문제는 별개이며, 이번 변경에서는 다루지 않음
  • 시스템 기본값에 의존하는 것은 좋지 않음. 가정과 달라질 수 있기 때문
  • 과거 우분투와 init.d 스크립트에서 문제가 있었음. 루트로 실행되는 Java 실행 스크립트가 일반 사용자와 다른 인코딩을 사용하여 문제 발생
  • 요즘은 덜 문제지만, OS에 이를 맡기는 것은 피해야 함. UTF-8 외 인코딩 사용은 의도치 않은 경우일 가능성이 높음
  • 명시적으로 지정하지 않고 OS 설정에 의존하는 것은 좋지 않음
  • 이번 변경은 좋은 방향. 깨지는 코드는 간단히 수정하는 게 나음
  • 내용 손상 버그의 가능성이 있는 상태로 두는 것보다 낫다고 봄

최근 수십 년 동안 점점 더 사실이 되어 가는 경험칙: "charset" 설정이 UTF-8이 아니라면 잘못된 것임

  • Python 2는 charset에 구애받지 않아 항상 잘 동작했지만, Python 3의 개선은 개선 그 이상이었음

  • Python 3 스크립트와 Python 2 스크립트를 구분하는 방법:

    • "utf-8" 문자열이 있으면 Python 3
    • 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 문자열은 인덱싱이 가능하지만 임의 접근은 드물기에 필요할 때 지연 인덱싱하는 게 좋을 듯

  • 한 칸씩 앞뒤로 이동만 하면 인덱스가 필요 없음

  • 따라서 내부적으로 UTF-8 표현이 가능할 것으로 보임

  • utf-8-sig가 아닌지? BOM을 선택적으로 처리해주는데 유용함

  • UTF-8과 관련하여, 리눅스 프레임버퍼는 오래전부터 제대로 된 UTF-8 지원이 있었어야 함

  • GNU Hurd는 2007년경부터 UTF-8을 지원하는 더 나은 '터미널 콘솔'을 가지고 있었음

  • 2024년인 지금에야 이런 변화가 오다니

  • 좋은 변화. 이제 JS만 UTF-8로 전환하면 되는데, 1995년에 쓰인 코드와 호환되어야 하기에 개선이 어려움

많은 유닉스 Python 개발자들이 기본 인코딩이 플랫폼마다 다르다는 걸 잊고, UTF-8 텍스트 파일을 읽을 때 encoding="utf-8"을 명시하지 않음

  • "잊는다"라기보다는 제대로 인지하지 못하는 것 같음
  • 명시적으로 요청하지 않는 한 Python이 모든 곳에서 UTF-8만 사용할 거라 생각했음