- Python 3.15는 UTF-8 모드를 기본으로 켜 파일, 표준 입출력, 파이프의 기본 인코딩을 UTF-8로 맞춤
- UTF-8은 소스 파일, JSON·TOML·YAML, 주요 편집기, 웹 데이터, Node.js·Go·Rust·Java 등에서 사실상 표준 인코딩으로 쓰이고 있어 상호운용성이 커짐
- 기존 기본 인코딩은 플랫폼에 따라 달라 Unix 개발자가
encoding="utf-8"을 생략하면 Windows 등에서 불일치 버그가 생길 수 있음 - 필요하면
PYTHONUTF8=0또는-X utf8=0으로 끌 수 있으며, 호환성 점검에는EncodingWarning,encoding="utf-8",encoding="locale",locale.getencoding()이 쓰임 - 기본 인코딩에 의존하는 프로그램은 주로 Windows에서
UnicodeError, mojibake, 조용한 데이터 손상을 겪을 수 있어 사전 점검이 필요함
Python 3.15에서 바뀌는 기본 인코딩
- PEP 686은 PEP 540의 UTF-8 모드를 기본값으로 활성화하는 변경임
- 기본 인코딩이 필요한 파일, stdio, 파이프에서 Python은 UTF-8을 일관되게 사용함
- Python 3.15부터 기본 활성화되며, 사용자는 다음 방식으로 비활성화할 수 있음
PYTHONUTF8=0-X utf8=0
UTF-8을 기본값으로 삼는 이유
- 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을 기본으로 사용함
- Python의 기본 인코딩이 UTF-8로 바뀌면 다른 도구·언어·데이터 형식과의 상호운용성이 좋아짐
- 많은 Unix 환경 Python 개발자는 기본 인코딩이 플랫폼 의존적이라는 점을 잊고, JSON·TOML·Markdown·Python 소스 파일처럼 UTF-8 텍스트를 읽을 때
encoding="utf-8"을 생략함 - 플랫폼별 기본 인코딩 차이는 이런 코드가 다른 환경에서 깨지는 버그 원인이 됨
locale API와 encoding="locale" 수정
- UTF-8 모드는
locale.getpreferredencoding(False)에 영향을 주므로, UTF-8 모드와 무관하게 locale 인코딩을 얻는 API가 필요함 locale.getencoding()은 이 목적을 위해 추가됐고, locale 인코딩을 반환하되 UTF-8 모드는 무시함- 이 API는 Python 3.11에 추가됨
warn_default_encoding옵션이 지정되면locale.getpreferredencoding()은open()처럼 PEP 597의EncodingWarning을 발생시킴- PEP 597은
TextIOWrapper에encoding="locale"옵션을 추가해 locale 인코딩을 명시적으로 지정할 수 있게 했음 - 기존에는 UTF-8 모드에서
encoding="locale"을 지정해도TextIOWrapper가"UTF-8"을 사용했음- 이는 PEP 597의 동기와 맞지 않았음
- Python의 기본 텍스트 인코딩이 바뀔 때 UTF-8 모드가 기본값이 되는 상황을 예상하지 못했기 때문임
- 이 불일치는 Python 3.11에서 수정됐고, UTF-8 모드에서도
encoding="locale"을 넘기면 locale 인코딩을 사용함
하위 호환성과 마이그레이션 절차
- 대부분의 Unix 시스템은 UTF-8 locale을 사용하고, Python은 locale이 C 또는 POSIX일 때 UTF-8 모드를 활성화하므로 변경 영향은 주로 Windows 사용자에게 집중됨
- 기본 인코딩에 의존하는 Python 프로그램은 다음 문제를 겪을 수 있음
UnicodeError- mojibake
- 조용한 데이터 손상
- 하위 호환성 문제를 고치는 권장 절차는 다음과 같음
- UTF-8 모드를 비활성화함
- PEP 597의
EncodingWarning으로 UTF-8 모드가 영향을 주는 위치를 찾음encoding옵션이 생략된 경우encoding="utf-8"또는encoding="locale"사용을 검토함locale.getpreferredencoding()을 사용한 경우"utf-8"또는locale.getencoding()사용을 검토함
- UTF-8 모드에서 애플리케이션을 테스트함
Ruby·Java 선행 사례와 거절된 대안
- Ruby는 Ruby 3.0, 2020년에 Windows의 기본
external_encoding을 UTF-8로 변경함 - Java는 JDK 18, 2022년에 기본 텍스트 인코딩을 UTF-8로 변경함
- Ruby와 Java 모두 하위 호환성을 위한 옵션은 제공하지만, Python의
EncodingWarning같은 기본 인코딩 사용 경고는 제공하지 않음 - 기본 인코딩 사용 자체를 폐기하는 방안은 거절됨
- ASCII 텍스트만 읽고 쓰는 용도로 기본 인코딩을 쓰는 경우가 많음
- Unix에서만 실행되는 비크로스플랫폼 애플리케이션에는 그런 경고가 유용하지 않음
- 모든 곳에
encoding을 강제하면 사용자 부담이 크고, 많은DeprecationWarning은 사용자가 경고를 무시하게 만들 수 있음 - PEP 387은 하위 호환성을 깨는 변경에 경고 추가를 요구하지만, 반드시
DeprecationWarning을 요구하지는 않음
subprocess모듈의 파이프 기본 인코딩으로PYTHONIOENCODING을 쓰는 방안도 거절됨- 이 방식은 UTF-8 모드에서도
subprocess.Popen(text=True)에 레거시 인코딩을 쓸 수 있게 함 - 하지만 “기본 인코딩”을 복잡하게 만들고, 이 방식 자체도 하위 호환성을 깨는 변경임
- 사용자는
text=True를encoding="utf-8"또는encoding="locale"로 바꿀 때까지 UTF-8 모드를 끌 수 있음
- 이 방식은 UTF-8 모드에서도
사용자 교육 관점
- 신규 사용자는 처음 1년 동안 텍스트 인코딩을 배울 필요가 줄어듦
- 비 UTF-8 텍스트 파일을 다뤄야 할 때 인코딩을 배우면 됨
- 기존 사용자는 하위 호환성 절차에 따라 영향을 받는 지점을 점검해야 함