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

Python 개선 제안 한국어 번역

PEP 263 – Python 소스 코드 인코딩 정의

Author:
Marc-André Lemburg <mal at lemburg.com>, Martin von Löwis <martin at v.loewis.de>
Status:
Final
Type:
Standards Track
Created:
06-Jun-2001
Python-Version:
2.3
Post-History:


Table of Contents

번역·라이선스 안내

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

초록

이 PEP는 Python 소스 파일의 인코딩을 선언하는 문법을 도입할 것을 제안합니다. 이 인코딩 정보는 Python 파서가 주어진 인코딩으로 파일을 해석하는 데 사용됩니다. 특히 소스 코드 안의 유니코드 리터럴 해석이 개선되고, 유니코드를 지원하는 편집기에서 UTF-8 같은 인코딩으로 유니코드 리터럴을 직접 작성할 수 있습니다.

문제

Python 2.1에서 유니코드 리터럴은 Latin-1 기반 인코딩인 “unicode-escape”로만 작성할 수 있습니다. 이 때문에 아시아의 많은 국가처럼 Latin-1이 아닌 로케일에서 생활하고 일하는 Python 사용자에게는 프로그래밍 환경이 상당히 불친절합니다. 프로그래머는 8비트 문자열을 원하는 인코딩으로 작성할 수 있지만, 유니코드 리터럴에는 “unicode-escape” 인코딩을 사용할 수밖에 없습니다.

제안하는 해결책

파일 맨 위에 인코딩을 선언하는 특수 주석을 두어, Python 소스 코드 인코딩을 소스 파일 단위로 드러내고 변경할 수 있게 할 것을 제안합니다.

Python이 이 인코딩 선언을 인식하게 하려면 Python 소스 코드 데이터 처리에 관해 여러 개념상의 변경이 필요합니다.

인코딩 정의하기

다른 인코딩 힌트가 주어지지 않으면 Python은 표준 인코딩으로 ASCII를 기본값으로 사용합니다.

소스 코드 인코딩을 정의하려면 소스 파일의 첫째 줄이나 둘째 줄에 다음과 같은 매직 주석을 넣어야 합니다.:

# coding=<encoding name>

또는 (널리 쓰이는 편집기가 인식하는 형식을 사용하면):

#!/usr/bin/python
# -*- coding: <encoding name> -*-

또는:

#!/usr/bin/python
# vim: set fileencoding=<encoding name> :

더 정확히 말하면, 첫째 줄이나 둘째 줄은 다음 정규 표현식과 일치해야 합니다.:

^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)

그러면 이 표현식의 첫 번째 그룹이 인코딩 이름으로 해석됩니다. Python이 알지 못하는 인코딩이면 컴파일 중에 오류가 발생합니다. 인코딩 선언이 있는 줄에는 Python 문이 있어서는 안 됩니다. 첫째 줄이 일치하면 둘째 줄은 무시됩니다.

유니코드 파일의 시작 부분에 유니코드 BOM 표시를 추가하는 Windows 같은 플랫폼을 지원하기 위해, UTF-8 시그니처 \xef\xbb\xbf도 (매직 인코딩 주석이 없더라도) ‘utf-8’ 인코딩으로 해석됩니다.

소스 파일이 UTF-8 BOM 표시 시그니처와 매직 인코딩 주석을 모두 사용하면, 주석에 허용되는 인코딩은 ‘utf-8’뿐입니다. 다른 인코딩을 지정하면 오류가 발생합니다.

예시

다음은 Python 소스 파일 맨 위에서 소스 코드 인코딩을 정의하는 여러 방식을 명확히 보여 주는 예입니다.

  1. 인터프리터 바이너리 줄이 있고 Emacs 방식의 파일 인코딩 주석을 사용하는 경우:
    #!/usr/bin/python
    # -*- coding: latin-1 -*-
    import os, sys
    ...
    
    #!/usr/bin/python
    # -*- coding: iso-8859-15 -*-
    import os, sys
    ...
    
    #!/usr/bin/python
    # -*- coding: ascii -*-
    import os, sys
    ...
    
  2. 인터프리터 줄 없이 일반 텍스트를 사용하는 경우:
    # This Python file uses the following encoding: utf-8
    import os, sys
    ...
    
  3. 텍스트 편집기마다 파일의 인코딩을 정의하는 방식이 다를 수 있습니다. 예를 들면 다음과 같습니다.:
    #!/usr/local/bin/python
    # coding: latin-1
    import os, sys
    ...
    
  4. 인코딩 주석이 없으면 Python 파서는 ASCII 텍스트로 가정합니다:
    #!/usr/local/bin/python
    import os, sys
    ...
    
  5. 작동하지 않는 인코딩 주석:
    1. “coding:” 접두사 누락:
      #!/usr/local/bin/python
      # latin-1
      import os, sys
      ...
      
    2. 인코딩 주석이 1행이나 2행에 없음:
      #!/usr/local/bin/python
      #
      # -*- coding: latin-1 -*-
      import os, sys
      ...
      
    3. 지원되지 않는 인코딩:
      #!/usr/local/bin/python
      # -*- coding: utf-42 -*-
      import os, sys
      ...
      

개념

이 PEP는 다음 개념을 기반으로 하며, 이러한 매직 주석을 사용할 수 있게 하려면 이 개념들을 구현해야 합니다:

  1. Python 소스 파일 전체는 하나의 인코딩을 사용해야 합니다. 서로 다르게 인코딩된 데이터를 포함하는 것은 허용되지 않으며, Python 소스 코드를 컴파일할 때 디코딩 오류가 발생합니다.

    위에서 설명한 방식으로 처음 두 행을 처리할 수 있는 인코딩이라면 어떤 인코딩이든 소스 코드 인코딩으로 허용되며, 여기에는 ASCII 호환 인코딩뿐 아니라 Shift_JIS 같은 일부 멀티바이트 인코딩도 포함됩니다. 예를 들어 UTF-16처럼 모든 문자에 2바이트 이상을 사용하는 인코딩은 포함되지 않습니다. 이는 토크나이저의 인코딩 감지 알고리즘을 단순하게 유지하기 위해서입니다.

  2. 이스케이프 시퀀스 처리는 지금과 같은 방식으로 계속 동작해야 하지만, 가능한 모든 소스 코드 인코딩에서 그렇게 동작해야 합니다. 즉, 표준 문자열 리터럴(8비트와 유니코드 모두)에서는 이스케이프 시퀀스가 확장되는 반면, 원시(raw) 문자열 리터럴에서는 이스케이프 시퀀스 중 매우 작은 일부만 확장됩니다.
  3. Python의 토크나이저/컴파일러 조합은 다음과 같이 동작하도록 갱신되어야 합니다.
    1. 파일을 읽습니다.
    2. 파일마다 고정된 인코딩을 가정하여 유니코드로 디코딩합니다.
    3. 이를 UTF-8 바이트 문자열로 변환합니다.
    4. UTF-8 내용을 토큰화합니다.
    5. 이를 컴파일합니다. 이때 주어진 유니코드 데이터로부터 유니코드 객체를 생성하고, 유니코드 리터럴 데이터로부터 문자열 객체를 생성할 때는 먼저 주어진 파일 인코딩을 사용해 UTF-8 데이터를 8비트 문자열 데이터로 다시 인코딩합니다.

Python 식별자는 인코딩의 ASCII 부분집합으로 제한되므로 4단계 이후에는 추가 변환이 필요하지 않다는 점에 유의하십시오.

구현

현재 인코딩을 선언하지 않고 문자열 리터럴에 비 ASCII 문자를 사용하는 기존 코드와의 하위 호환성을 위해, 구현은 두 단계로 도입됩니다:

  1. 인코딩 선언이 없으면 내부적으로 “iso-8859-1” 선언으로 취급하여, 문자열 리터럴과 주석에 비 ASCII 문자를 허용합니다. 이렇게 하면 임의의 바이트 문자열이 처리 과정의 2단계와 5단계 사이에서 올바르게 왕복 변환되며, 비 ASCII 바이트를 포함하는 유니코드 리터럴에 대해 Python 2.2와의 호환성을 제공합니다.

    입력에서 비 ASCII 바이트가 발견되면, 올바르게 인코딩되지 않은 입력 파일마다 한 번씩 경고가 발생합니다.

  2. 경고를 제거하고, 기본 인코딩을 “ascii”로 변경합니다.

내장 compile() API는 유니코드를 입력으로 받을 수 있도록 개선됩니다. 8비트 문자열 입력에는 위에서 설명한 표준 인코딩 감지 절차가 적용됩니다.

인코딩 선언이 포함된 유니코드 문자열이 compile()에 전달되면 SyntaxError가 발생합니다.

SUZUKI Hisao가 패치를 작업하고 있습니다. 자세한 내용은 [2]를 참조하십시오. 1단계만 구현한 패치는 [1]에서 구할 수 있습니다.

단계

위의 1단계와 2단계는 기본 인코딩을 “ascii”로 변경하는 것을 제외하고 2.3에서 구현이 완료되었습니다.

기본 인코딩은 2.5 버전에서 “ascii”로 설정되었습니다.

범위

이 PEP는 현재의 (다소) 정의되지 않은 소스 코드 인코딩 상황에서 더 견고하고 이식성 있는 정의로 나아가는 업그레이드 경로를 제공하고자 합니다.

참고 문헌

역사

  • 1.10 이상: CVS 이력을 참조하십시오.
  • 1.8: coding 정규식에 ‘.’를 추가했습니다.
  • 1.7: 1단계 구현에 경고를 추가했습니다. Latin-1 기본 인코딩을 인터프리터의 기본 인코딩으로 대체했습니다. compile()에 대한 조정을 추가했습니다.
  • 1.4 - 1.6: 사소한 조정
  • 1.3: Martin v. Loewis의 의견을 반영했습니다: UTF-8 BOM 표시 감지, Emacs 스타일 매직 주석, 구현에 대한 2단계 접근 방식