PEP 687 – 표준 라이브러리의 모듈 격리
- Author:
- Erlend Egeberg Aasland <erlend at python.org>, Petr Viktorin <encukou at gmail.com>
- Discussions-To:
- Discourse thread
- Status:
- Final
- Type:
- Standards Track
- Requires:
- 489, 573, 630
- Created:
- 04-Apr-2022
- Python-Version:
- 3.12
- Post-History:
- 04-Apr-2022, 11-Apr-2022
- Resolution:
- Discourse message
번역·라이선스 안내
이 비공식 한국어 번역은 원문 Copyright 절의 Public Domain or CC0-1.0, whichever is more permissive 조건에 따라 제공합니다. 원저자와 공식 원문은 그대로 표시합니다. 수정되지 않은 기준 원문 · 공식 최신판
초록
표준 라이브러리의 확장 모듈은 다단계 초기화(PEP 489)로 전환되며, 가능한 경우 모든 상태는 프로세스 전역 변수가 아닌 모듈 객체에 저장됩니다.
소급 적용에 관한 참고 사항
이 제안의 상당 부분은 이미 구현되었습니다. 변경 사항을 설명하고, 그 변경이 바람직한지에 대한 합의를 구하고, 남은 변경 사항을 제안하고, 새 모듈을 위한 모범 사례를 정하기 위해 이 PEP를 제출합니다.
동기 및 근거
정보성 PEP인 PEP 630은 제안된 변경 사항이 (표준 라이브러리뿐 아니라) 모든 확장 모듈에 일반적으로 적용될 때의 배경, 동기, 근거, 영향 및 구현 참고 사항을 설명합니다.
그 문서는 이 제안에서 빼놓을 수 없는 부분입니다. 먼저 읽으십시오.
이 PEP는 표준 라이브러리에 특화된 사항을 다룹니다.
명세
PEP 630의 본문은 Python 문서의 HOWTO로 전환되며, 해당 PEP는 폐기(Final로 표시)됩니다.
표준 라이브러리의 모든 확장 모듈은 PEP 489에서 도입된 다단계 초기화로 전환됩니다.
모든 표준 라이브러리 확장 모듈은 격리될 것입니다. 즉, 다음과 같습니다:
- 모듈이 정의하는 타입, 함수 및 기타 객체는 불변이거나, 다른 모듈 인스턴스와 공유되지 않습니다.
- 모듈에 특화된 상태는 전역 상태를 나타내는 경우가 아니라면 다른 모듈 인스턴스와 공유되지 않습니다.
예를 들어,
_csv.field_size_limit은 모듈별 숫자를 가져오거나 설정합니다. 반면에readline.get_history_item이나os.getpid같은 함수는 계속해서 프로세스 전역 상태(모듈 외부에 있으며, Python이 아닌 라이브러리를 포함한 다른 라이브러리와 공유될 수 있는 상태)를 다룹니다.
힙 타입으로의 전환
모듈 상태에 접근할 필요가 없고 전환해야 할 다른 이유도 없는 정적 타입은 정적 타입으로 남아야 합니다.
메서드가 자신의 모듈 인스턴스에 접근해야 하는 타입은 다음 사항을 고려하여 PEP 630에 따라 힙 타입으로 전환됩니다:
- 이전에 정적 타입이었던 모든 표준 라이브러리 타입은 불변으로 유지되어야 합니다. 힙 타입은 불변성을 유지하기 위해
Py_TPFLAGS_IMMUTABLE_TYPE플래그를 사용하여 정의해야 합니다. bpo-43908을 참조하십시오.테스트는 불변 타입에 새 속성을 만들려고 할 때
TypeError가 발생하는지 확인해야 합니다. tp_new = NULL인 정적 타입에는 공개 생성자가 없지만, 힙 타입은 베이스 클래스로부터 생성자를 상속합니다. 이전에 인스턴스화할 수 없었던 타입이 그 특성을 유지하도록 하십시오.Py_TPFLAGS_DISALLOW_INSTANTIATION을 사용하십시오.test.support.check_disallow_instantiation()을 사용하는 테스트를 추가하십시오. bpo-43916을 참조하십시오.- 변환된 힙 타입이 의도치 않게 직렬화 가능(
pickle가능)해질 수 있습니다. 변환 전후에pickle.dumps를 호출한 결과가 같은지 테스트하고, 테스트가 실패하면TypeError를 발생시키는__reduce__메서드를 추가하십시오. 예시는 PR-21002를 참고하십시오.
이러한 문제는 향후 변환 작업에 도움이 되도록 Devguide에 추가될 것입니다.
다른 종류의 문제가 발견되면, 해결책을 찾아 Devguide에 추가하고 이미 변환된 모듈을 점검하여 수정할 때까지 해당 모듈은 변경하지 않아야 합니다.
절차
다음 절차는 Devguide에 추가되어야 하며, 모든 모듈이 변환될 때까지 유지되어야 합니다. 새로 발견된 사항은 모두 그곳이나 일반 HOWTO에 문서화해야 합니다.
1부: 준비
- 버그 트래커나 Discourse에서 논의를 시작하십시오. 모듈 유지 관리자 및/또는 코드 소유자를 참여시키십시오. 변경의 이유와 근거를 설명하십시오.
- 전역 상태로 인한 성능 병목 지점을 파악하십시오. 개념 증명 구현을 만들고 성능 영향을 측정하십시오.
pyperf는 벤치마킹에 좋은 도구입니다. - 구현 계획을 세우십시오. 타입이 적은 작은 모듈이라면 PR 하나로 충분할 수 있습니다. 타입이 많고 외부 라이브러리 콜백도 있을 수 있는 더 큰 모듈이라면 여러 개의 PR이 필요할 것입니다.
2부: 구현
참고: 이것은 다른 모듈에서 얻은 교훈을 바탕으로 복잡한 모듈을 위해 제안하는 구현 계획입니다. 더 작은 모듈에서는 자유롭게 단순화하십시오.
- 가능한 곳에는 Argument Clinic(인자 클리닉)을 추가하십시오. 그러면 정의 클래스를 사용해 타입 메서드에서 모듈 상태를 쉽게 가져올 수 있습니다.
- 모듈 상태를 준비하십시오. 모듈 상태
struct를 만들고, 그 인스턴스를 정적 전역 변수로 추가하고, 모듈 상태를 가져오기 위한 헬퍼 스텁을 만드십시오. - 관련 전역 변수를 모듈 상태
struct에 추가하고, 전역 상태에 접근하는 코드가 대신 모듈 상태 헬퍼를 사용하도록 수정하십시오. 이 단계는 여러 개의 PR로 나눌 수 있습니다. - 필요한 경우 정적 타입을 힙 타입으로 변환하십시오.
- 전역 모듈 상태 구조체를 실제 모듈 상태로 변환하십시오.
- 다단계 초기화를 구현하십시오.
4단계부터 6단계까지는 가급적 하나의 알파 개발 단계 안에 반영되어야 합니다.
하위 호환성
이제 표준 라이브러리의 확장 모듈을 두 번 이상 로드할 수 있게 됩니다. 예를 들어, 이러한 모듈을 sys.modules에서 삭제한 뒤 다시 임포트하면, 이전에 로드된 어떤 인스턴스와도 격리된 새 모듈 인스턴스가 생성됩니다.
이는 이전 동작을 전제로 한 코드에 영향을 줄 수 있습니다. 이전에는 확장 모듈의 전역 변수가 처음 로드된 모듈에서 얕게 복사되었습니다.
보안 영향
알려진 바 없습니다.
교육 방법
이 제안의 상당 부분은 숙련된 사용자를 대상으로 하는 HOWTO이며, 이 내용은 문서로 옮겨질 예정입니다.
초보자는 영향을 받지 않을 것입니다.
참조 구현
변경 사항 대부분은 현재 다음 이슈들에 대한 커밋으로 main 브랜치에 반영되어 있습니다:
- bpo-40077, 정적 타입을 힙 타입으로 변환: PyType_FromSpec() 사용
- bpo-46417, 임베디드 Python을 위해 Py_Finalize()에서 정적 타입 정리
- bpo-1635741, Py_Finalize()가 종료 시 모든 Python 객체를 정리하지 않음
예를 들어, _csv 모듈에서 이루어진 변경 및 수정 사항은 다음과 같습니다:
Copyright
This document is placed in the public domain or under the CC0-1.0-Universal license, whichever is more permissive.