Following system colour scheme Selected dark colour scheme Selected light colour scheme

Python 개선 제안 한국어 번역

PEP 624 – Py_UNICODE 인코더 API 제거

Author:
Inada Naoki <songofacandy at gmail.com>
Status:
Final
Type:
Standards Track
Created:
06-Jul-2020
Python-Version:
3.11
Post-History:
08-Jul-2020

Table of Contents

번역·라이선스 안내

이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판

초록

이 PEP는 Python 3.11에서 사용 중단된 Py_UNICODE인코더 API를 제거할 것을 제안합니다:

  • PyUnicode_Encode()
  • PyUnicode_EncodeASCII()
  • PyUnicode_EncodeLatin1()
  • PyUnicode_EncodeUTF7()
  • PyUnicode_EncodeUTF8()
  • PyUnicode_EncodeUTF16()
  • PyUnicode_EncodeUTF32()
  • PyUnicode_EncodeUnicodeEscape()
  • PyUnicode_EncodeRawUnicodeEscape()
  • PyUnicode_EncodeCharmap()
  • PyUnicode_TranslateCharmap()
  • PyUnicode_EncodeDecimal()
  • PyUnicode_TransformDecimalToASCII()

Note

PEP 623에서는 Py_UNICODE와 관련된 유니코드 객체 API를 제거할 것을 제안합니다. 반면 이 PEP는 유니코드 객체와 관련되지 않습니다. 이 PEP들은 서로 다른 동기를 가지고 있으며 서로 다른 논의가 필요하기 때문에 분리되어 있습니다.

동기

일반적으로 오랫동안 사용 중단되었고 사용자가 거의 없는 API의 수를 줄이는 것은 CPython의 유지 관리성을 향상할 뿐만 아니라 API 사용자와 다른 Python 구현에도 도움이 되므로 좋은 생각입니다.

근거

Python 3.3부터 사용 중단됨

Py_UNICODE와 이를 사용하는 API는 Python 3.3부터 사용 중단되었습니다.

비효율적

이러한 API는 모두 PyUnicode_FromWideChar를 사용하여 구현됩니다. 따라서 사용자가 유니코드 객체를 인코딩하려 할 때 이러한 API는 비효율적입니다.

널리 사용되지 않음

상위 4000개 PyPI 패키지를 검색했을 때 [1], pyodbc만 이러한 API를 사용합니다.

  • PyUnicode_EncodeUTF8()
  • PyUnicode_EncodeUTF16()

pyodbc는 이러한 API를 사용하여 Unicode 객체를 bytes 객체로 인코딩합니다. 따라서 수정하기 쉽습니다. [2]

대체 API

Py_UNICODE * 대신 PyObject *unicode를 받아들이는 대체 API가 있습니다. 사용자는 이러한 API로 마이그레이션할 수 있습니다.

사용 중단된 API 대체 API
PyUnicode_Encode() PyUnicode_AsEncodedString()
PyUnicode_EncodeASCII() PyUnicode_AsASCIIString() (1)
PyUnicode_EncodeLatin1() PyUnicode_AsLatin1String() (1)
PyUnicode_EncodeUTF7() (2)
PyUnicode_EncodeUTF8() PyUnicode_AsUTF8String() (1)
PyUnicode_EncodeUTF16() PyUnicode_AsUTF16String() (3)
PyUnicode_EncodeUTF32() PyUnicode_AsUTF32String() (3)
PyUnicode_EncodeUnicodeEscape() PyUnicode_AsUnicodeEscapeString()
PyUnicode_EncodeRawUnicodeEscape() PyUnicode_AsRawUnicodeEscapeString()
PyUnicode_EncodeCharmap() PyUnicode_AsCharmapString() (1)
PyUnicode_TranslateCharmap() PyUnicode_Translate()
PyUnicode_EncodeDecimal() (4)
PyUnicode_TransformDecimalToASCII() (4)

참고:

  1. const char *errors매개변수가 누락되었습니다.
  2. 공개된 대체 API가 없습니다. 그러나 사용자는 일반적인 PyUnicode_AsEncodedString()을 대신 사용할 수 있습니다.
  3. const char *errors, int byteorder 매개변수가 누락되어 있습니다.
  4. 직접적인 대체 항목이 없습니다. 그러나 Py_UNICODE_TODECIMAL을 대신 사용할 수 있습니다. CPython은 유니코드에서 숫자로 변환할 때 대신 _PyUnicode_TransformDecimalAndSpaceToASCII를 사용합니다.

계획

Python 3.11에서 이러한 API를 제거합니다. 이러한 API는 이미 사용 중단으로 지정되었습니다.

  • PyUnicode_Encode()
  • PyUnicode_EncodeASCII()
  • PyUnicode_EncodeLatin1()
  • PyUnicode_EncodeUTF7()
  • PyUnicode_EncodeUTF8()
  • PyUnicode_EncodeUTF16()
  • PyUnicode_EncodeUTF32()
  • PyUnicode_EncodeUnicodeEscape()
  • PyUnicode_EncodeRawUnicodeEscape()
  • PyUnicode_EncodeCharmap()
  • PyUnicode_TranslateCharmap()
  • PyUnicode_EncodeDecimal()
  • PyUnicode_TransformDecimalToASCII()

대체 아이디어

Py_UNICODE*PyObject*로 교체합니다.

“Alternative APIs” 섹션에서 설명한 대로, 일부 API에는 PyObject *unicode입력을 허용하는 공개 대체 API가 없습니다. 또한 일부 공개 대체 API에는 errorsbyteorder매개변수가 없는 등의 제약이 있습니다.

사용 중단된 API를 제거하는 대신, 해당 이름을 공개 대체 API에 재사용할 수 있습니다.

이미 비공개 대체 API가 있으므로, 비공개 이름을 공개 이름 및 사용 중단된 이름으로 변경하기만 하면 됩니다.

다음으로 이름 변경 다음에서 이름 변경
PyUnicode_EncodeASCII() _PyUnicode_AsASCIIString()
PyUnicode_EncodeLatin1() _PyUnicode_AsLatin1String()
PyUnicode_EncodeUTF7() _PyUnicode_EncodeUTF7()
PyUnicode_EncodeUTF8() _PyUnicode_AsUTF8String()
PyUnicode_EncodeUTF16() _PyUnicode_EncodeUTF16()
PyUnicode_EncodeUTF32() _PyUnicode_EncodeUTF32()

장점:

  • 더욱 일관된 API 집합을 갖게 됩니다.

단점:

  • 하위 호환성이 없습니다.
  • 드문 사용 사례를 위해 유지 관리해야 하는 공개 API가 더 많아집니다.
  • 기존 공개 API로 대부분의 사용 사례를 처리할 수 있으며, 다른 경우에는 PyUnicode_AsEncodedString()을 사용할 수 있습니다.

Py_UNICODE*Py_UCS4*로 바꾸기

Py_UNICODEPy_UCS4로 바꾸고 이러한 API의 사용 중단을 철회할 수 있습니다.

UTF-8, UTF-16, UTF-32 인코더는 내부적으로 Py_UCS4를 지원합니다. 따라서 PyUnicode_EncodeUTF8(), PyUnicode_EncodeUTF16(), PyUnicode_EncodeUTF32()는 임시 유니코드 객체를 생성하지 않아도 됩니다.

장점:

  • Py_UCS4*에서 UTF-8, UTF-16, UTF-32 코덱을 사용하여 바이트 객체로 인코딩할 때 임시 유니코드 객체를 생성하지 않아도 됩니다.

단점:

  • 하위 호환성이 없습니다.
  • 드문 사용 사례를 위해 유지 관리해야 할 공개 API가 더 많습니다.
  • Python/C API를 지원하려는 다른 Python 구현도 이 API들을 지원해야 합니다.
  • 향후 유니코드 내부 표현을 UTF-8로 변경한다면, 이러한 API에 대해서만 UCS-4 지원을 유지해야 합니다.

Py_UNICODE*wchar_t*로 대체

Py_UNICODEwchar_t로 대체할 수 있습니다. Py_UNICODE가 이미 wchar_t의 typedef이므로, 이는 현재 상태입니다.

sizeof(wchar_t) == 4인 플랫폼에서는, UTF-8, UTF-16 및 UTF-32 코덱을 사용하여 wchar_t*에서 바이트 객체로 인코딩할 때 임시 유니코드 객체를 생성하지 않을 수 있습니다. 이는 “Py_UNICODE*Py_UCS4*로 대체” 아이디어와 같습니다.

장점:

  • 하위 호환성이 유지됩니다.
  • sizeof(wchar_t) == 4인 플랫폼에서 UTF-8, UTF-16 및 UTF-32 코덱을 사용하여 Py_UCS4*에서 바이트 객체로 인코딩할 때 임시 유니코드 객체를 생성하지 않을 수 있습니다.

단점:

  • Windows가 wchar_t를 많이 사용하는 가장 주요한 플랫폼이지만, Windows에서는 sizeof(wchar_t) == 2이므로 이러한 API는 항상 임시 유니코드 객체를 생성해야 합니다.
  • 드문 사용 사례를 위해 유지 관리해야 할 공개 API가 더 많습니다.
  • Python/C API를 지원하려는 다른 Python 구현도 이 API들을 지원해야 합니다.
  • 향후 유니코드 내부 표현을 UTF-8로 변경한다면, 이러한 API에 대해서만 UCS-4 지원을 유지해야 합니다.

기각된 아이디어

런타임 경고 발생

기존 컴파일러 경고에 더해 런타임 DeprecationWarning을 발생시키는 방안이 제안되었습니다.

그러나 이러한 API는 현재 GIL을 해제하지 않습니다. 이러한 API에서 경고를 발생시키는 것은 안전하지 않습니다. 다음 예를 참조하십시오.

PyObject *u = PyList_GET_ITEM(list, i);  // u is borrowed reference.
PyObject *b = PyUnicode_EncodeUTF8(PyUnicode_AS_UNICODE(u),
        PyUnicode_GET_SIZE(u), NULL);
// Assumes u is still living reference.
PyObject *t = PyTuple_Pack(2, u, b);
Py_DECREF(b);
return t;

PyUnicode_EncodeUTF8()에서 Python 경고를 발생시키면 경고 필터와 다른 스레드가 list를 변경할 수 있으며, uPyUnicode_EncodeUTF8()가 반환된 후 댕글링 참조가 될 수 있습니다.

논의

반대 의견

  • 이러한 API를 제거하면 임시 유니코드 없이 코덱을 사용할 수 있는 기능이 사라집니다.
    • Python 3.3 이후로 코덱은 임시 유니코드 객체 없이 유니코드 버퍼를 직접 인코딩할 수 없습니다. 현재 이러한 API는 모두 임시 유니코드 객체를 생성합니다. 따라서 이를 제거해도 어떤 기능도 줄어들지 않습니다.
  • 디코더 API도 함께 제거하지 않는 이유는 무엇입니까?
    • 이들은 안정 ABI의 일부입니다.
    • PyUnicode_DecodeASCII()PyUnicode_DecodeUTF8()은 매우 널리 사용됩니다. 이를 폐지할 만큼의 가치는 없습니다.
    • 디코더 API는 임시 바이트 객체를 생성하지 않고 바이트 버퍼에서 직접 디코딩할 수 있습니다. 반면에 인코더 API는 임시 유니코드 객체를 피할 수 없습니다.

참고 자료