PEP 399 – 순수 Python/C 가속 모듈 호환성 요구 사항
- Author:
- Brett Cannon <brett at python.org>
- Status:
- Final
- Type:
- Informational
- Created:
- 04-Apr-2011
- Python-Version:
- 3.3
- Post-History:
- 04-Apr-2011, 12-Apr-2011, 17-Jul-2011, 15-Aug-2011, 01-Jan-2013
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
CPython의 Python 표준 라이브러리에는 순수 Python과 C 양쪽으로 (전체 또는 부분적으로) 구현된 모듈이 여럿 있습니다. 이 PEP는 이러한 경우 C 코드가 합리적으로 가능한 한 그대로 대체할 수 있는 구현으로 동작하도록, 순수 Python 코드에 사용되는 테스트 스위트를 반드시 통과할 것을 요구합니다(C 및 VM 전용 테스트는 예외입니다). 또한 순수 Python으로 된 동등한 구현이 없는 새로운 C 기반 모듈을 표준 라이브러리에 추가하려면 특별한 허가를 받아야 합니다.
근거
Python은 CPython 가상 머신(VM)을 넘어 성장했습니다. IronPython, Jython, PyPy는 모두 현재 CPython VM의 실용적인 대안입니다. Python 프로그래밍 언어를 중심으로 생겨난 VM 생태계 덕분에 Python은 CPython을 사용할 수 없는 여러 다양한 분야에서 사용되고 있습니다. 예를 들어 Jython을 사용하면 Java 애플리케이션에서 Python을 사용할 수 있습니다.
CPython 이외의 모든 VM이 직면하는 문제는 (어느 정도) C로 구현된 표준 라이브러리 모듈을 다루는 일입니다. 다른 VM은 일반적으로 C API of CPython을 전부 지원하지 않으므로, 해당 모듈을 만드는 데 사용된 코드를 사용할 수 없습니다. 이 때문에 다른 VM들은 흔히 해당 모듈을 순수 Python으로 다시 구현하거나, VM 자체를 구현하는 데 사용된 프로그래밍 언어(예: IronPython의 경우 C#)로 다시 구현하게 됩니다. CPython, PyPy, Jython, IronPython 사이의 이러한 중복 작업은 매우 안타까운 일이며, 모듈을 최소한 순수 Python으로 구현해 두면 이 중복 작업을 줄이는 데 도움이 됩니다.
이 PEP의 목적은 특별한 허가가 주어지지 않는 한 Python 표준 라이브러리에 추가되는 모든 새 모듈이 반드시 순수 Python 구현을 갖추도록 의무화하여 이러한 중복 작업을 최소화하는 것입니다. 이를 통해 표준 라이브러리에 있는 모듈을 CPython뿐 아니라 모든 VM에서 사용할 수 있게 됩니다(이 요구 사항을 충족하지 않는 기존 모듈은 예외로 하지만, 누군가 나중에 순수 Python 구현을 추가하는 것을 막지는 않습니다).
성능상의 이유로 모듈의 일부(또는 전체)를 (CPython의 경우) C로 다시 구현하는 것은 여전히 허용되지만, 그러한 가속 코드는 의미를 검증하고 동작이 어긋나는 것을 막기 위해 동일한 테스트 스위트(VM 또는 C 전용 테스트 제외)를 통과해야 합니다. 이를 위해 가속 코드를 추가하기 전에 해당 모듈의 테스트 스위트가 순수 Python 구현을 포괄적으로 커버해야 합니다.
세부 사항
Python 3.3부터 표준 라이브러리에 추가되는 모든 모듈은 순수 Python 구현을 갖추어야 합니다. 이 규칙은 Python 개발 팀이 해당 모듈에 특별 예외를 허가한 경우에만 무시할 수 있습니다. 일반적으로 예외는 모듈이 특정 C 기반 라이브러리(예: sqlite3)를 감싸는 경우에만 허가됩니다. 예외를 허가할 때에는 해당 모듈이 CPython 전용으로 간주되며, 다른 VM이 지원할 것으로 기대되는 Python 표준 라이브러리의 일부가 아니라는 점이 인정됩니다. C 라이브러리에 대한 API를 제공하기 위해 ctypes를 사용하는 것은 계속해서 권장되지 않습니다. ctypes에는 특정 오류(예: API 변경)가 발생하지 않도록 C 코드가 일반적으로 의존하는 컴파일러 보장이 없기 때문입니다.
이 PEP가 순수 Python 구현을 의무화하더라도, 함께 제공되는 가속 모듈의 사용을 배제하는 것은 아닙니다. 가속 모듈을 제공하는 경우, 그 이름은 가속 대상 모듈의 이름 앞에 밑줄을 접두사로 붙인 것이어야 합니다. 예를 들어 warnings에 대해서는 _warnings입니다. 순수 Python 구현에서 가속 코드에 접근하는 일반적인 패턴은 from _warnings import *처럼 import *로 가져오는 것입니다. 이는 보통 모듈의 끝에서 수행하여, 특정 Python 객체를 가속된 동등한 객체로 덮어쓸 수 있도록 합니다. 이러한 import는 필요한 경우 모듈의 끝보다 앞에서 수행할 수도 있습니다. 예를 들어 가속된 베이스 클래스가 제공되고 이를 Python 코드에서 서브클래싱하는 경우입니다. 이 PEP는 순수 Python 대응 모듈이 없는 표준 라이브러리의 기존 모듈에 그러한 모듈을 추가하도록 강제하지 않습니다. 그러나 누군가 자발적으로 순수 Python으로 된 동등한 구현을 제공하고 유지 관리한다면(예: PyPy 팀이 csv 모듈의 순수 Python 구현을 제공하고 유지 관리하겠다고 나서는 경우) 그러한 코드는 받아들여집니다. 그러한 경우 기대되는 의미 측면에서는 C 버전을 참조 구현으로 간주합니다.
새로 추가되는 모든 가속 코드는 합리적인 범위에서 순수 Python 구현에 최대한 가까운 드롭인 대체물로 동작해야 합니다. 가속 코드를 제공하는 VM의 기술적 세부 사항은 필요하면 달라도 됩니다. 예를 들어, C로 구현하면 클래스가 type이 되는 경우가 그렇습니다. Python 코드와 이에 대응하는 C 코드가 최대한 비슷하게 동작하는지 검증하기 위해, 두 코드베이스 모두 순수 Python 코드에 적용되는 것과 같은 테스트로 테스트해야 합니다(C 코드나 특정 VM에만 해당하는 테스트는 이 요구 사항에 포함되지 않습니다). 기대하는 의미를 검증할 수 있도록 테스트 스위트는 광범위해야 합니다.
드롭인 대체물로 동작한다는 것은 순수 Python 코드에 존재하지 않는 공개 API를 가속 코드에서 제공해서는 안 된다는 뜻이기도 합니다. 이 요구 사항이 없으면, 사람들이 순수 Python 구현을 사용하는 다른 VM에서는 제공되지 않는 가속 코드의 세부 사항에 의도치 않게 의존하게 될 수 있습니다. 의미적 동등성이라는 계약이 지켜지는지 검증할 수 있도록, 모듈은 가속 코드를 사용하는 경우와 사용하지 않는 경우 모두 최대한 철저하게 테스트해야 합니다.
예를 들어, 모듈의 순수 Python 버전과 C 가속 버전을 모두 실행하는 테스트를 작성하려면 다음과 같은 기본 관용구를 따를 수 있습니다:
from test.support import import_fresh_module
import unittest
c_heapq = import_fresh_module('heapq', fresh=['_heapq'])
py_heapq = import_fresh_module('heapq', blocked=['_heapq'])
class ExampleTest:
def test_example(self):
self.assertTrue(hasattr(self.module, 'heapify'))
class PyExampleTest(ExampleTest, unittest.TestCase):
module = py_heapq
@unittest.skipUnless(c_heapq, 'requires the C _heapq module')
class CExampleTest(ExampleTest, unittest.TestCase):
module = c_heapq
if __name__ == '__main__':
unittest.main()
테스트 모듈은 self.heapq 클래스 속성을 통해 heapq 모듈에 접근하는 테스트 메서드를 가진 베이스 클래스(ExampleTest)와 이 속성을 각각 Python 버전 또는 C 버전의 모듈로 설정하는 두 개의 서브클래스를 정의합니다. 두 서브클래스만 unittest.TestCase를 상속한다는 점에 유의하십시오. 이렇게 하면 unittest 테스트 탐색이 ExampleTest 클래스를 TestCase 서브클래스로 감지하지 않습니다. C 모듈을 사용할 수 없을 때 이 테스트들을 건너뛰도록 C 코드를 테스트하는 클래스에 skipUnless 데코레이터를 추가할 수 있습니다.
이 테스트가 순수 Python 구현의 heapq.heappop()에 대해 광범위한 커버리지를 제공한다면, 가속 C 코드를 CPython 표준 라이브러리에 추가할 수 있습니다. 그렇지 않다면 가속 C 코드를 추가하기 전에 적절한 커버리지를 갖출 때까지 테스트 스위트를 보강해야 합니다.
호환성을 높이는 데에도 도움이 되도록, C 코드는 특정 타입에 뜻하지 않게 의존하지 않게 객체에 대해 추상 API를 사용해야 합니다. 예를 들어, 함수가 시퀀스를 받는다면 C 코드는 PyList_GetItem() 같은 함수 대신 기본적으로 PyObject_GetItem()을 사용해야 합니다. 적절한 PyList_CheckExact()를 사용한다면 C 코드에 빠른 경로(fast path)를 두어도 됩니다. 하지만 그 밖의 경우 API는 특정 타입만이 아니라 덕 타이핑으로 적절한 인터페이스를 갖춘 모든 객체와 함께 동작해야 합니다.
Copyright
This document has been placed in the public domain.