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

Python 개선 제안 한국어 번역

PEP 303 – 여러 제수를 사용하는 divmod() 확장

Author:
Thomas Bellman <bellman+pep-divmod at lysator.liu.se>
Status:
Rejected
Type:
Standards Track
Created:
31-Dec-2002
Python-Version:
2.3
Post-History:


Table of Contents

번역·라이선스 안내

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

초록

이 PEP는 내장 divmod() 함수의 확장을 설명하며, 여러 제수를 받아 여러 divmod() 호출을 하나로 연결할 수 있도록 합니다.

결정

이 PEP는 거부되었습니다. 연결된 divmod()의 대부분의 사용 사례는 일정한 모듈러스를 포함하며(예를 들어 기수 변환에서), 이러한 경우에는 루프로 작성하는 편이 더 적절합니다. 초를 일/시/분/초로 나누는 예제는 월과 연도에는 일반화되지 않습니다. 오히려 전체 사용 사례를 날짜 및 시간 모듈이 더 유연하고 견고하게 처리합니다. PEP에서 언급한 다른 사용 사례는 실제 코드에서는 다소 드뭅니다. 이 제안은 명확성과 직관성 측면에서도 문제가 있습니다. 예제에서는 인자의 순서가 올바른지 또는 대상 튜플의 길이가 적절한지 즉시 명확하지 않습니다. 다른 언어를 사용하는 사용자는 문서를 다시 읽지 않고도 표준적인 두 인자 형식을 이해할 가능성이 더 높습니다. 2005년 6월 17일의 python-dev 토론 [1] 을 참조하십시오.

사양

내장 divmod() 함수는 여러 제수를 받도록 변경되며, 시그니처도 divmod(dividend, divisor) 에서 divmod(dividend, *divisors) 로 변경됩니다. 피제수를 마지막 제수로 나누어 몫과 나머지를 구합니다. 그런 다음 몫을 뒤에서 두 번째 제수로 나누어 새로운 몫과 나머지를 구합니다. 모든 제수를 사용할 때까지 이 과정을 반복하며, 이후 divmod() 는 마지막 단계의 몫과 모든 단계의 나머지로 구성된 튜플을 반환합니다.

새로운 divmod() 동작의 Python 구현은 다음과 같을 수 있습니다.:

def divmod(dividend, *divisors):
    modulos = ()
    q = dividend
    while divisors:
        q, r = q.__divmod__(divisors[-1])
        modulos = (r,) + modulos
        divisors = divisors[:-1]
    return (q,) + modulos

동기

때때로 이전 단계의 몫에 divmod() 를 호출하면서 제수가 달라지는 일련의 divmod() 연산을 수행하고 싶을 수 있습니다. 가장 일반적인 경우는 아마도 일정한 초의 수를 주, 일, 시, 분, 초로 변환하는 것입니다. 현재는 이를 다음과 같이 작성합니다.:

def secs_to_wdhms(seconds):
    m, s = divmod(seconds, 60)
    h, m = divmod(m, 60)
    d, h = divmod(h, 24)
    w, d = divmod(d, 7)
    return (w, d, h, m, s)

필요할 때마다 이를 작성하는 것은 번거롭고 실수하기 쉽습니다.

대신 제안에 따라 divmod() 내장 함수를 변경하면, 초를 주, 일, 시, 분, 초로 변환하는 코드는 다음과 같이 됩니다.

def secs_to_wdhms(seconds):
    w, d, h, m, s = divmod(seconds, 7, 24, 60, 60)
    return (w, d, h, m, s)

이렇게 하면 입력하기도 쉽고, 올바르게 입력하기도 쉬우며, 읽기도 쉽습니다.

다른 응용 사례는 다음과 같습니다.

  • 천문학적 각도(적위는 도, 분, 초로 측정하고, 적경은 시, 분, 초로 측정합니다).
  • 옛 영국 통화(1파운드 = 20실링, 1실링 = 12펜스).
  • 앵글로색슨식 길이 단위: 1마일 = 1760야드, 1야드 = 3피트, 1피트 = 12인치입니다.
  • 앵글로색슨식 무게 단위: 1롱톤 = 160스톤, 1스톤 = 14파운드, 1파운드 = 16온스, 1온스 = 16드램입니다.
  • 영국식 부피 단위: 1갤런 = 4쿼트, 1쿼트 = 2파인트, 1파인트 = 20액량 온스입니다.

근거

이 아이디어는 APL에서 나온 것으로, APL에는 이러한 동작을 하는 연산자가 있습니다. (그 연산자가 어떻게 생겼는지는 기억나지 않으며, 어차피 ASCII로 표현하는 것은 불가능할 것입니다.)

APL 연산자는 두 번째 피연산자로 리스트를 받지만, 이 PEP는 각 제수를 divmod() 함수의 별도 인자로 전달할 것을 제안합니다. 이는 주로 가장 흔한 사용 사례에서 제수가 호출 안에 바로 상수로 (위의 7, 24, 60, 60처럼) 들어갈 것으로 예상되며, 괄호나 대괄호를 추가하면 호출문만 지저분해지기 때문입니다.

divmod()의 두 번째 인자로 명시적인 시퀀스를 요구하면 하위 호환성이 심각하게 깨질 것입니다. divmod()가 두 번째 인자가 시퀀스인지 검사하도록 만드는 것은 고려하기에도 너무 볼썽사나운 것으로 여겨집니다. 그리고 다른 곳에서 계산된 시퀀스를 실제로 가지고 있는 경우에는, 대신 divmod(x, *divs)를 작성하는 것으로 충분히 쉽게 처리할 수 있습니다.

최소 하나의 제수를 요구하는 것, 즉 divmod(x)를 거부하는 것도 고려되었으나, 그렇게 해야 할 마땅한 이유가 떠오르지 않았기에 일반성을 위해 허용됩니다.

제수 없이 divmod()를 호출해도 여전히 (요소가 하나인) 튜플을 반환해야 합니다. 그렇지 않으면, 가변 개수의 제수로 divmod()를 호출하여 “알 수 없는” 개수의 요소를 갖는 반환값을 얻는 코드는 그 경우를 특별히 처리해야 할 것입니다. 제수 없이 divmod()를 호출한다는 것을 알고 있는 코드에서는 특별한 경우 처리를 정당화하기에는 너무 사소한 것으로 간주됩니다.

제수를 반대 방향으로, 즉 마지막 제수로 먼저 나누는 대신 첫 번째 제수로 먼저 나누도록 처리하는 방식도 고려되었습니다. 그러나 결과는 가장 유효한 부분이 맨 앞에, 가장 덜 유효한 부분이 맨 뒤에 오게 되며 (연쇄된 divmod를 숫자를 “자릿수”로 나누는 방법으로, 각기 다른 가중치를 갖는다고 생각해 보십시오), 제수(가중치)를 결과와 같은 순서로 지정하는 것이 합리적입니다.

역연산:

def inverse_divmod(seq, *factors):
    product = seq[0]
    for x, y in zip(factors, seq[1:]):
        product = product * x + y
    return product

도 유용할 수 있습니다. 그러나

seconds = (((((w * 7) + d) * 24 + h) * 60 + m) * 60 + s)

을 작성하는 것은 연쇄된 divmod보다 작성하기도 읽기도 덜 번거롭습니다. 따라서 이는 덜 중요한 것으로 간주되며, 그 도입은 별도의 PEP로 미룰 수 있습니다. 또한, 그러한 함수에는 좋은 이름이 필요하지만, 이 PEP 저자는 아직 하나도 떠올리지 못했습니다.

문자열이 나눗셈도 나머지 연산도 지원하지 않음에도 불구하고, divmod("spam")을 호출해도 오류가 발생하지 않습니다. 그러나 다른 객체도 알지 못하는 한 divmod()가 작동할지 여부를 판단할 수 없으므로, 이를 금지하는 것은 부질없어 보입니다.

하위 호환성

__builtin__ 모듈의 divmod() 함수를 대체하는 모듈이 있다면, 새 문법을 사용하는 다른 모듈이 깨질 수 있습니다. 이는 매우 드문 경우로 예상됩니다.

두 개의 인자 외의 다른 형태로 divmod()를 호출할 때 TypeError 예외가 발생할 것으로 예상하는 코드는 깨질 것입니다. 이 또한 매우 드문 경우로 예상됩니다.

하위 호환성과 관련된 다른 문제는 알려진 바 없습니다.

참조 구현

아직 완료되지는 않았으나, Python/bltinmodule.cbuiltin_divmod() 함수를 상당히 직관적으로 새롭게 구현하면 될 것으로 보입니다.

참고 자료