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

Python 개선 제안 한국어 번역

PEP 310 – 신뢰할 수 있는 획득/해제 쌍

Author:
Michael Hudson <mwh at python.net>, Paul Moore <p.f.moore at gmail.com>
Status:
Rejected
Type:
Standards Track
Created:
18-Dec-2002
Python-Version:
2.4
Post-History:


Table of Contents

번역·라이선스 안내

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

초록

다음과 같은 코드를 타이핑을 덜 하면서 작성할 방법이 있으면 좋을 것입니다:

the_lock.acquire()
try:
    ....
finally:
    the_lock.release()

이 PEP는 하나의 문법(‘with’ 블록)과 위의 내용을 일반화하는 “소문자 i” 인터페이스를 제안합니다.

결정

이 PEP는 PEP 343이 채택됨에 따라 거부되었습니다.

근거

Python의 예외 처리 철학이 가진 장점 중 하나는 “잘못된” 일(예: 어떤 시스템 호출의 반환값을 확인하지 않는 일)을 하기 어렵게 만든다는 점입니다. 현재 이 장점은 자원 정리에는 적용되지 않습니다. 자원(예: 잠금)을 획득하고 해제하는 현재 문법은 다음과 같습니다:

the_lock.acquire()
try:
    ....
finally:
    the_lock.release()

이 문법은 획득과 해제 사이에 (어쩌면 큰) 코드 블록을 두기 때문에, 코드가 자원을 올바르게 관리하는지 “한눈에” 확인하기 어렵습니다. 또 다른 흔한 실수는 “acquire” 호출을 try 블록 안에 작성하는 것인데, 이렇게 하면 획득에 실패했을 때 잠금이 잘못 해제됩니다.

기본 문법과 의미

‘with’ 문의 문법은 다음과 같습니다:

'with' [ var '=' ] expr ':'
    suite

이 문은 다음과 같은 일련의 문과 동등한 것으로 정의됩니다:

var = expr

if hasattr(var, "__enter__"):
    var.__enter__()

try:
    suite

finally:
    var.__exit__()

(with: 문에 부적절한 객체를 사용하면 오류가 발생하도록, __exit__ 메서드의 존재 여부는 __enter__와 달리 확인하지 않습니다).

변수를 생략하면 이름 없는 객체가 스택에 할당됩니다. 이 경우 스위트는 이름 없는 객체에 접근할 수 없습니다.

가능한 확장

Python Developers 리스트에서는 기본 문법에 대한 여러 가지 확장 가능성이 논의되었습니다. 이 확장안들 중 어느 것도 이 PEP가 제안하는 해결책에 포함되지 않습니다. 많은 경우, 찬반 양쪽의 논거를 이루는 인자들이 거의 똑같이 강력합니다. 그런 경우 이 PEP는 항상 단순함을 택했는데, 그 이유는 단지 더 강력한 기능이 필요한 곳에서는 기존의 try 블록을 사용할 수 있기 때문입니다.

여러 개의 표현식

한 가지 제안은 하나의 ‘with’ 문 안에 여러 개의 표현식을 허용하자는 것이었습니다. __enter__ 메서드는 왼쪽에서 오른쪽으로, __exit__ 메서드는 오른쪽에서 왼쪽으로 호출됩니다. 이렇게 하는 것의 장점은, 둘 이상의 자원을 관리할 때 ‘with’ 문을 중첩하면 코드가 오른쪽 여백 쪽으로 점점 밀려나는 문제를 피할 수 있다는 것입니다. 이 문제의 해결책은 다른 모든 깊은 중첩의 경우와 같습니다. 코드의 일부를 별도의 함수로 분리하면 됩니다. 게다가 __exit__ 메서드 중 하나가 예외를 일으키면 어떻게 되는지(다른 __exit__ 메서드를 호출해야 하는지)의 문제도 해결해야 합니다.

예외 처리

예외가 발생했을 때 호출되며 그 예외를 처리하거나 다시 발생시킬 수 있는 선택적 __except__ 핸들러를 포함하도록 프로토콜을 확장하자는 제안이 있었습니다. 이 확장의 의미를 정확하고 이해하기 쉽게 정의할 수 있을지는 전혀 분명하지 않습니다. 예를 들어, 예외 핸들러가 정의되어 있으면 동등한 코드가 try ... except ... else가 되고, 그렇지 않으면 try ... finally가 되어야 합니까? 일반적으로 이를 컴파일 시점에 어떻게 결정할 수 있습니까? 다른 방안은 코드가 try ... finally 안의 try ... except로 전개되도록 정의하는 것입니다. 하지만 이는 실제 상황에서 올바르게 동작하지 않을 수 있습니다.

예외 처리에 대해 확인된 유일한 사용 사례는 트랜잭션 처리(정상적으로 끝나면 커밋하고, 예외가 발생하면 롤백)입니다. 이는 아마 기존의 try ... except ... else 블록으로도 똑같이 쉽게 처리할 수 있으므로, 이 PEP는 예외 핸들러에 대한 지원을 전혀 포함하지 않습니다.

구현 참고 사항

with 문과 동등하다고 명시된 코드에는 잠재적인 경쟁 조건이 있습니다. 예를 들어, __enter__ 메서드 호출이 완료된 시점과 try 블록이 시작되는 시점 사이에 KeyboardInterrupt 예외가 발생하면 __exit__ 메서드가 호출되지 않습니다. 이는 자원 누수나 교착 상태로 이어질 수 있습니다. [XXX Guido는 이런 종류의 경쟁 조건에 신경 쓰고 있으며, 이를 처리하기 위한 C 마법을 작성할 생각이라고 밝혔습니다. ‘with’ 문의 구현도 이를 따라야 합니다.]

미해결 문제

기존 클래스(예를 들어 파일류 객체와 잠금)에 적절한 __enter__ 및 __exit__ 메서드를 추가해야 합니까? 찬성하는 명백한 이유는 편의성(어댑터가 필요 없음)입니다. 반대 측 논거의 핵심 인자는, 내장 파일에는 이것이 있지만 (예를 들어) StringIO에는 없다면 파일 객체에 “with”를 사용하는 코드를 StringIO 객체에서는 재사용할 수 없다는 점입니다. 따라서 __exit__ = close는 “파일류 객체” 프로토콜의 일부가 되며, 사용자 정의 클래스도 이를 지원해야 할 수 있습니다.

__enter__ 훅은 불필요할 수도 있습니다. 많은 사용 사례에서 어댑터 클래스가 필요한데, 그 경우 __enter__ 훅이 하는 작업은 __init__ 훅에서도 똑같이 쉽게 할 수 있습니다.

객체의 수명을 명시적으로 제어하는 방법이 있다면, __exit__ 훅 함수가 하는 역할을 기존의 __del__ 훅이 대신 맡을 수 있을 것입니다. 이 접근법의 지지자와 이메일을 주고받은 결과 [1] 저자 중 한 명은 이것이 올바른 생각이 아니라는 확신을 더욱 굳히게 되었습니다…

“with …” 구문의 “즉시 사용 가능한 유용성”을 높이기 위해, “__exit__” 메서드의 이름을 “close”로 하거나, __exit__ 메서드가 없으면 “close” 메서드를 고려하자는 제안이 있었습니다 [2].

‘with …’ 블록과 제너레이터 사이에는 개념상 몇 가지 유사점이 있으며, 이로 인해 for 루프로 with 블록의 기능을 구현할 수 있다는 제안이 나왔습니다 [3]. 어떤 면에서는 깔끔하지만, 저희는 for 루프는 루프로 남아야 한다고 생각합니다.

대안 아이디어

IEXEC: Holger Krekel – XML 비슷한 문법을 사용하는 일반화된 접근 방식(URL을 찾지 못했습니다…).

Holger는 감시 대상 블록의 제어 흐름에 대한 세부 정보를 전달받는 “실행 모니터”에 대해 훨씬 더 원대한 아이디어를 가지고 있습니다. 흥미롭기는 하지만, 이 아이디어들은 언어를 깊고 미묘한 방식으로 바꿀 수 있으므로 별도의 PEP에서 다루어야 합니다.

Smalltalk/Ruby의 익명 블록 방식 확장이라면 어느 것이든 당연히 이 제안을 포괄합니다.

PEP 319도 같은 영역에 속하지만, python-dev에 제기되었을 때 지지를 얻지 못했습니다.

하위 호환성

이 PEP는 새로운 키워드를 제안하므로 __future__ 절차를 거쳐야 할 것입니다.

도입 비용

언어가 점점 더 커지고 복잡해진다고 주장하는 사람들에게는 불평할 거리가 하나 더 생깁니다. 가르쳐야 할 것도 하나 더 늘어납니다.

이 제안이 유용하려면 표준 라이브러리와 그 밖의 코드에 있는 파일 같은 클래스와 잠금 같은 클래스 상당수에

__exit__ = close

또는 이와 비슷한 것이 추가되어야 합니다.

미도입 비용

올바른 코드를 작성하는 일에는 여전히 잘못된 코드를 작성하는 일보다 더 많은 노력이 듭니다.

참고 문헌

여기에서 언급할 만한 python-list 및 python-dev 논의가 여러 가지 있습니다.