PEP 686 – UTF-8 모드를 기본값으로 설정
- Author:
- Inada Naoki <songofacandy at gmail.com>
- Discussions-To:
- Discourse thread
- Status:
- Final
- Type:
- Standards Track
- Created:
- 18-Mar-2022
- Python-Version:
- 3.15
- Post-History:
- 18-Mar-2022, 31-Mar-2022
- Resolution:
- Discourse message
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
이 PEP는 UTF-8 모드를 기본적으로 활성화할 것을 제안합니다.
이 변경으로 Python은 파일, 표준 입출력 및 파이프의 기본 인코딩에 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"을 지정하지 않습니다. 일관되지 않은 기본 인코딩은 많은 버그를 유발합니다.
사양
기본적으로 UTF-8 모드 활성화
Python은 Python 3.15부터 기본적으로 UTF-8 모드를 활성화합니다.
사용자는 PYTHONUTF8=0 또는 -X utf8=0를 설정하여 UTF-8 모드를 계속 비활성화할 수 있습니다.
locale.getencoding()
UTF-8 모드는 locale.getpreferredencoding(False)에 영향을 미치므로, UTF-8 모드와 관계없이 로케일 인코딩을 가져올 API가 필요합니다.
이 목적을 위해 locale.getencoding()을 추가합니다. 이 함수는 로케일 인코딩도 반환하지만 UTF-8 모드는 무시합니다.
warn_default_encoding 옵션이 지정되면 locale.getpreferredencoding()은 open()과 마찬가지로 EncodingWarning을 발생시킵니다( PEP 597도 참조하십시오).
이 API는 Python 3.11에서 추가되었습니다.
encoding="locale" 옵션 수정
PEP 597은 TextIOWrapper에 encoding="locale" 옵션을 추가했습니다. 이 옵션은 로케일 인코딩을 명시적으로 지정하는 데 사용됩니다. TextIOWrapper는 옵션이 지정된 경우 기본 텍스트 인코딩과 관계없이 로케일 인코딩을 사용해야 합니다.
그러나 현재는 encoding="locale"이 지정되어 있더라도 UTF-8 모드에서 TextIOWrapper는 "UTF-8"을 사용합니다. 이 동작은 PEP 597의 동기와 일치하지 않습니다. 이는 Python이 기본 텍스트 인코딩을 변경할 때 UTF-8 모드를 기본값으로 설정할 것으로 예상하지 않았기 때문입니다.
UTF-8 모드를 기본값으로 설정하기 전에 이러한 불일치를 수정해야 합니다. UTF-8 모드에서도 encoding="locale"이 전달된 경우 TextIOWrapper는 로케일 인코딩을 사용해야 합니다.
이 문제는 Python 3.11에서 수정되었습니다.
하위 호환성
대부분의 Unix 시스템은 UTF-8 로케일을 사용하며, Python은 로케일이 C 또는 POSIX일 때 UTF-8 모드를 활성화합니다. 따라서 이 변경은 주로 Windows 사용자에게 영향을 줍니다.
Python 프로그램이 기본 인코딩에 의존하는 경우, 이 변경으로 인해 UnicodeError, 모지바케 또는 심지어 조용한 데이터 손상이 발생할 수 있습니다. 따라서 이 변경은 널리 공지해야 합니다.
다음은 이 하위 호환성 문제를 해결하기 위한 지침입니다.
- UTF-8 모드를 비활성화하십시오.
- UTF-8 모드의 영향을 받는 모든 위치를 찾으려면
EncodingWarning(PEP 597)을 사용하십시오.encoding옵션을 생략한 경우,encoding="utf-8"또는encoding="locale"을 사용하십시오.locale.getpreferredencoding()을 사용하는 경우,"utf-8"또는locale.getencoding()을 사용하십시오.
- UTF-8 모드로 애플리케이션을 테스트하십시오.
이전 사례
- Ruby는 Ruby 3.0(2020)에서 Windows의 기본
external_encoding을 UTF-8로 변경했습니다. - Java는 JDK 18(2022)에서 기본 텍스트 인코딩을 UTF-8로 변경했습니다.
Ruby와 Java 모두 하위 호환성을 위한 옵션이 있습니다. 두 언어는 기본 인코딩 사용에 대해 Python의 PEP 597의 EncodingWarning과 같은 경고를 제공하지 않습니다.
거부된 대안
암시적 인코딩 사용 중단
기본 인코딩 사용을 중단하는 방안이 고려됩니다.
그러나 기본 인코딩이 ASCII 텍스트만 읽고 쓰는 데 사용되는 경우가 많습니다. 또한 Unix에서 실행되는 크로스 플랫폼이 아닌 애플리케이션에는 이러한 경고가 유용하지 않습니다.
따라서 사용자가 모든 곳에서 encoding을 지정하도록 강제하는 것은 너무 번거롭습니다. 많은 DeprecationWarning을 발생시키면 사용자가 경고를 무시하게 됩니다.
PEP 387은 하위 호환성이 깨지는 변경 사항에 대한 경고를 추가하도록 요구합니다. 그러나 DeprecationWarning을 사용하도록 요구하지는 않습니다. 따라서 선택적인 EncodingWarning을 사용하는 것은 PEP 387을 위반하지 않습니다.
Java도 JEP 400에서 이 아이디어를 거부했습니다.
PIPE에 PYTHONIOENCODING 사용
하위 호환성 문제를 완화하기 위해 subprocess 모듈에서 PYTHONIOENCODING을 PIPE의 기본 인코딩으로 사용하는 방안이 고려됩니다.
이 아이디어를 사용하면 UTF-8 모드에서도 subprocess.Popen(text=True)에 레거시 인코딩을 사용할 수 있습니다.
그러나 이 아이디어는 “기본 인코딩”을 복잡하게 만듭니다. 그리고 이 아이디어는 하위 호환성도 없습니다.
따라서 이 아이디어는 거부됩니다. 사용자는 text=True를 encoding="utf-8" 또는 encoding="locale"로 바꿀 때까지 UTF-8 모드를 비활성화할 수 있습니다.
이것을 가르치는 방법
신규 사용자의 경우 이 변경으로 가르쳐야 할 내용이 줄어듭니다. 사용자는 첫해에 텍스트 인코딩을 배울 필요가 없습니다. UTF-8이 아닌 텍스트 파일을 사용해야 할 때 이를 배워야 합니다.
기존 사용자는 Backward Compatibility 섹션을 참조하십시오.
참고 자료
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.