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

Python 개선 제안 한국어 번역

PEP 331 – 로케일 독립적인 부동소수점/문자열 변환

Author:
Christian R. Reis <kiko at async.com.br>
Status:
Final
Type:
Standards Track
Created:
19-Jul-2003
Python-Version:
2.4
Post-History:
21-Jul-2003, 13-Aug-2003, 18-Jun-2004

Table of Contents

번역·라이선스 안내

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

초록

Python 2.3에서 LC_NUMERIC 로케일 범주에 대한 지원은 Python 영역에서만 구현되어 있습니다. 이 때문에 문자열에서 부동소수점 수를 파싱하고 생성하는, C로 구현된 확장 모듈과 라이브러리를 사용하는 애플리케이션에서 일관되지 않은 동작과 스레드 안전성 문제가 발생합니다. 이 문서는 필요에 따라 로케일에 구애받지 않는 대체 함수를 제공하고 사용함으로써 이러한 불일치를 없애는 계획을 제안합니다.

소개

Python은 locale 모듈을 통해 범용 지역화 서비스를 제공하며, 이 모듈로 숫자 타입의 표시와 변환 과정을 로케일에 맞게 지역화할 수 있습니다. LC_TIME과 LC_COLLATE 같은 로케일 범주를 사용하면 애플리케이션의 어떤 측면을 지역화할지 정밀하게 설정할 수 있습니다.

LC_NUMERIC 범주는 float 숫자와 고정 소수점 숫자의 소수점 구분자처럼, 통화가 아닌 숫자 정보의 형식을 지정합니다. LC_NUMERIC 범주의 지역화는 현재 Python 영역에서만 구현되어 있으며, Python 런타임에서 호출되는 C 라이브러리는 Python의 LC_NUMERIC 설정을 알지 못합니다. 이는 Python 파서와 관련 코드에서 사용하는 일부 저수준 함수의 동작이 바뀌지 않도록 하기 위한 것입니다 [2].

그러나 이 때문에 C 라이브러리를 감싸는 확장 모듈에 문제가 생깁니다. 이러한 확장 모듈을 사용하는 애플리케이션은 부동소수점 값을 일관되지 않게 표시하고 변환합니다.

PyGTK [3]의 작성자인 James Henstridge는 setlocale() 함수에 스레드 안전성 문제도 있다고 추가로 지적했습니다. 어떤 스레드가 GIL 밖에서 C 라이브러리의 setlocale()을 호출하면 Python이 부동소수점 수를 잘못 파싱하고 생성할 수 있기 때문입니다.

근거

LC_NUMERIC에 대한 Python 지역화와 C 라이브러리 지역화 사이의 불일치는 C 확장을 사용하는 모든 지역화된 애플리케이션에서 문제가 됩니다. 문제의 정확한 양상은 애플리케이션마다 다르겠지만, 부동소수점 값을 파싱하거나 서식화할 때 발생할 가능성이 가장 높습니다.

문제 예시

이 PEP를 작성하게 된 최초의 문제는 PyGTK 모듈이 감싸고 있는 GTK+ UI 툴킷의 GtkSpinButton [4] 위젯과 관련이 있습니다. 이 위젯은 숫자 모드로 설정할 수 있으며, 그러면 위젯에 입력된 문자는 숫자로 평가됩니다.

LC_NUMERIC이 C 로케일의 표준과 다른 float 구분자를 쓰는 로케일로 설정되면 문제가 발생합니다(예를 들어 브라질 로케일 pt_BR은 ‘.’ 대신 ‘,’를 사용합니다). LC_NUMERIC이 libc 수준에서 설정되지 않기 때문에, 스핀버튼의 텍스트 입력란에 float 값이 ‘.’를 구분자로 사용하여 잘못 표시됩니다. 또한 ‘,’ 구분자로 소수 값을 입력할 수 없습니다.

이 작은 예시는 이 툴킷을 사용하는 지역화된 애플리케이션을 Python으로 작성하면 사용성이 떨어진다는 것을 보여 줍니다.

제안

Martin v. Löwis는 python-dev에서 이 문제의 해결책이 받아들여지기 위한 초기 제약 조건에 대해 다음과 같이 의견을 밝혔습니다:

  • 파서를 망가뜨리지 않고 C 라이브러리 수준에서 LC_NUMERIC을 설정할 수 있어야 합니다.
  • float()와 str() 함수는 로케일을 인식하지 않는 상태로 유지되어야 합니다.
  • 로케일을 인식하는 str()과 atof() 함수는 locale 모듈에 남아 있어야 합니다.

Python 소스를 분석한 결과, 현재 다음 함수들은 LC_NUMERIC이 C 로케일로 설정되어 있어야 제대로 동작하는 것으로 보입니다:

  • Python/compile.c:parsenumber()
  • Python/marshal.c:r_object()
  • Objects/complexobject.c:complex_to_buf()
  • Objects/complexobject.c:complex_subtype_from_string()
  • Objects/floatobject.c:PyFloat_FromString()
  • Objects/floatobject.c:format_float()
  • Objects/stringobject.c:formatfloat()
  • Modules/stropmodule.c:strop_atof()
  • Modules/cPickle.c:load_float()

제안하는 방식은 float 형식에서 변환하는 함수(strtod()/atof())와 float 형식으로 변환하는 함수(snprintf())를 LC_NUMERIC에 영향을 받지 않도록 구현하는 것입니다. 그리고 사용자가 지정한 로케일에 따라 형식이 달라지면 안 되는 곳에서는 이 함수를 사용합니다.

로케일(locale) 모듈도 LC_NUMERIC에 대한 특수 처리를 제거하도록 변경해야 합니다.

이 변경으로 앞서 언급한 스레드 안전성 문제도 해결될 것입니다.

잠재적인 코드 기여

이 문제는 처음에 GTK+ 라이브러리의 문제로 보고되었으나 [5], 이후 Python 구현의 비일관성으로 올바르게 진단되었습니다. 그런데 다행스러운 우연으로, glib 라이브러리(주로 GTK+를 위해 개발되었으며, GNU C 라이브러리와 혼동하지 마십시오)는 이 문서에서 제시한 것과 비슷한 이유로 LC_NUMERIC 설정과 무관한 함수를 여럿 구현하고 있습니다(예시는 [6] 참고).

같은 GTK+ 문제 보고에서 Havoc Pennington은 glib 저자들이 이 코드를 PSF에 기꺼이 기여할 것이라고 제안했으며, 그렇게 되면 이 PEP의 구현이 상당히 간단해질 것입니다. glib 코드의 원저자인 Alex Larsson은 코드를 안전하게 통합할 수 있도록 2003-08-20 [8]에 PSF 기여자 동의서 [7]를 제출했으며, 이 동의서는 접수되어 승인되었습니다.

위험 요소

제공된 로케일 독립 함수에 크로스 플랫폼 문제가 있을 수 있습니다. 다만 제공된 코드는 부동 소수점 숫자에 가해진 로케일 의존적 변경을 되돌리기만 하므로 이 위험은 낮습니다.

Martin과 Guido는 기여된 코드에 잠재적인 저작권 문제가 있다고 지적했습니다. GTK+ 및 glib 팀 구성원들이 코드의 라이선스 변경에 문제가 없다고 밝혔고, 이를 확실히 하기 위해 PSF 기여자 동의서도 우편으로 제출되었으므로, 저는 이 부분에서 문제가 없을 것이라고 생각합니다.

Tim Peters는 스레딩과 관련된 상황 중에는 제안된 변경만으로 문제를 완전히 해결하기에 충분하지 않은 경우가 있다고 지적했습니다 [9]. 그러나 완전한 해결책은 현재 존재하지 않습니다.

구현

Gustavo Carneiro <gjc at inescporto.pt>가 구현을 개발하여 Sourceforge.net 버그 774665 [10]에 첨부했습니다.

최종 패치 [11]는 Python CVS에 통합되었으며, 이를 통합한 사람은 Martin v. Löwis가 버그 보고서에 명시된 대로 2004-06-08에 Python CVS에 통합했습니다.

참고 문헌