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

Python 개선 제안 한국어 번역

PEP 328 – 임포트: 여러 줄 및 절대/상대

Author:
Aahz <aahz at pythoncraft.com>
Status:
Final
Type:
Standards Track
Created:
21-Dec-2003
Python-Version:
2.4, 2.5, 2.6
Post-History:
08-Mar-2004

Table of Contents

번역·라이선스 안내

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

초록

import문에는 두 가지 문제가 있습니다.

  • import문은 작성하기 어려울 수 있으며, 파이썬다운 스타일 지침에 맞추려면 여러 가지 무리한 방법을 사용해야 합니다.
  • 패키지가 관련된 경우 임포트는 모호할 수 있습니다. 패키지 내부에서는 import foo가 패키지 내부의 모듈을 가리키는지, 패키지 외부의 어떤 모듈을 가리키는지 명확하지 않습니다. (더 정확히 말하면, 로컬 모듈이나 패키지가 sys.path에 직접 매달린 다른 항목을 가릴 수 있습니다.)

첫 번째 문제에 대해서는 여러 이름을 괄호로 묶을 수 있도록 허용하여, 파이썬의 표준 여러 줄 값 작성 방식을 적용할 수 있도록 제안합니다. 두 번째 문제에 대해서는 모든 import문을 기본적으로 절대 임포트로 만들고(sys.path만 검색), 패키지 상대 임포트에 액세스하기 위한 특수 구문(앞에 점을 붙이는 방식)을 제공할 것을 제안합니다.

일정

Python 2.5에서는 다음을 사용하여 새로운 절대 임포트 동작을 활성화해야 합니다.

from __future__ import absolute_import

상대 임포트를 자유롭게 사용할 수 있습니다. Python 2.6에서는 패키지 내부 임포트가 발생하는 모든 import문이 DeprecationWarning을 발생시킵니다(상대 임포트 구문을 사용하지 않는 from <> import에도 적용됩니다).

괄호 사용의 근거

현재 모듈이나 패키지에서 많은 이름을 임포트하려면, 달갑지 않은 여러 선택지 중 하나를 골라야 합니다.

  • 백슬래시 연속을 사용하여 긴 줄 작성:
    from Tkinter import Tk, Frame, Button, Entry, Canvas, Text, \
        LEFT, DISABLED, NORMAL, RIDGE, END
    
  • 여러 import문 작성:
    from Tkinter import Tk, Frame, Button, Entry, Canvas, Text
    from Tkinter import LEFT, DISABLED, NORMAL, RIDGE, END
    

(import *는 선택 사항이 아닙니다 ;-)

대신 파이썬의 표준 그룹화 메커니즘인 괄호를 사용하여 import문을 작성할 수 있어야 합니다.:

from Tkinter import (Tk, Frame, Button, Entry, Canvas, Text,
    LEFT, DISABLED, NORMAL, RIDGE, END)

이 제안의 이 부분은 처음부터 BDFL의 승인을 받았습니다.

Python 2.4에 괄호 지원이 추가되었습니다.

절대 임포트의 근거

Python 2.4 및 이전 버전에서는 패키지 내부에 있는 모듈을 읽을 때 다음 중 어느 것을 가리키는지 명확하지 않습니다.

import foo

최상위 모듈을 가리키거나 패키지 내부의 다른 모듈을 가리킵니다. 파이썬 라이브러리가 확장됨에 따라 기존 패키지 내부 모듈이 점점 더 많이 표준 라이브러리 모듈을 갑자기 우연히 가리게 됩니다. 어떤 모듈을 의미하는지 지정할 방법이 없기 때문에 패키지 내부에서는 특히 해결하기 어려운 문제입니다. 이 모호성을 해결하기 위해 foo는 항상 sys.path에서 도달할 수 있는 모듈 또는 패키지가 되도록 제안합니다. 이를 절대 임포트라고 합니다.

python-dev 커뮤니티는 절대 임포트가 더 일반적인 사용 사례이고, 절대 임포트가 상대 임포트(패키지 내부 임포트)의 모든 기능을 제공할 수 있기 때문에 기본값으로 선택했습니다. 다만 계층 구조에서 더 상위에 있는 패키지 구성 요소의 이름을 변경하거나 한 패키지를 다른 패키지 내부로 이동할 때는 어려움이 따릅니다.

이는 의미론의 변경을 나타내므로 Python 2.5와 2.6에서는 다음을 사용하여 절대 임포트를 선택 사항으로 제공합니다.

from __future__ import absolute_import

이 제안의 이 부분은 처음부터 BDFL의 승인을 받았습니다.

상대 임포트의 근거

절대 임포트로 전환되면서 상대 임포트를 허용해야 하는지에 대한 의문이 제기되었습니다. 몇 가지 사용 사례가 제시되었으며, 그중 가장 중요한 것은 서브패키지를 수정하지 않고도 대규모 패키지의 구조를 재배치할 수 있다는 점입니다. 또한 패키지 내부의 모듈은 상대 임포트 없이는 자신을 쉽게 임포트할 수 없습니다.

귀도는 상대 임포트라는 아이디어를 승인했지만, 표기법(구문)에 대해서는 많은 의견 차이가 있었습니다. 상대 임포트에서는 임포트할 특정 이름을 나열해야 한다는 데에는 합의가 이루어진 듯합니다. (즉, 독립적인 항으로서의 import foo는 항상 절대 임포트가 됩니다.)

다음은 제안된 방식들입니다:

  • 귀도가 제안한 하나:
    from .foo import bar
    

    그리고

    from ...foo import bar
    

    이 두 형식에는 서로 다른 의미론이 몇 가지 제안되었습니다. 한 가지 의미론은 각 점이 한 단계에 해당하도록 만드는 것입니다. 점의 개수를 세기가 어렵다는 불만이 많았습니다. 또 다른 방법은 상대 임포트를 한 단계만 허용하는 것입니다. 그러면 많은 기능을 놓치게 되며, 사람들은 한 점 형식에서 점을 빠뜨리는 문제에 대해서도 여전히 불만을 제기했습니다. 마지막 방법은 상대 모듈과 패키지를 찾는 알고리즘을 정의하는 것입니다. 이에 대한 반론은 “명시적인 것이 암시적인 것보다 낫다”는 것입니다. (제안된 알고리즘은 “현재 패키지 디렉터리에서 시작하여 최상위 패키지 부모에 도달할 때까지 위로 검색한다”는 것입니다.)

    일부 사람들은 “-“나 “^”와 같은 다른 문장 부호를 구분자로 사용하자고 제안했습니다.

    일부 사람들은 “*”를 사용하자고 제안했습니다.:

    from *.foo import bar
    
  • 다음 선택지 묶음은 여러 게시자가 제안한 내용을 합친 것입니다.:
    from __pkg__.__pkg__ import
    

    그리고

    from .__parent__.__parent__ import
    

    많은 사람(귀도 포함)은 이것들이 보기 흉하다고 생각하지만, 이것들은 are명확하고 명시적입니다. 전반적으로 더 많은 사람은 더 짧은 선택지인 __pkg__를 선호합니다.

  • 한 가지 제안은 형제 참조만 허용하자는 것이었습니다. 즉, 상대 임포트를 사용하여 패키지 트리에서 더 높은 위치에 있는 모듈을 참조할 수 없게 됩니다. 그러면 다음 중 하나를 사용할 수 있습니다.
    from .spam import eggs
    

    또는

    import .spam.eggs
    
  • 일부 사람들은 인덱스를 사용한 부모 참조를 허용하는 방식을 선호합니다.:
    from -2.spam import eggs
    

    이 시나리오에서 현재 디렉터리에서 임포트하는 것은 간단한

    from .spam import eggs
    
  • 마지막으로, 패키지 내부로 들어가려 할 때 importfrom ... import로 변경해야 하는 방식을 싫어하는 사람들도 있습니다. 이들은 import구문을 완전히 다시 작성하자고 제안합니다.:
    from MODULE import NAMES as RENAME searching HOW
    

    또는

    import NAMES as RENAME from MODULE searching HOW
        [from NAMES] [in WHERE] import ...
    

    그러나 이는 Python 2.5에서는 구현할 수 없을 가능성이 매우 높고(변경 규모가 너무 큼), 상대 임포트를 허용하는 일은 충분히 중요하므로 지금 무언가가 필요합니다(표준 import문이 절대 임포트로 변경될 예정이기 때문입니다). 더 나아가, 이 제안된 구문에는 아직 해결되지 않은 몇 가지 질문이 있습니다.

    • 제안된 구문은 정확히 무엇입니까? (어떤 상황에서 어떤 절이 선택 사항입니까?)
    • searching 절이 얼마나 강하게 결합됩니까? 다시 말해, 다음과 같이 작성합니까?:
      import foo as bar searching XXX, spam as ham searching XXX
      

      아니면:

      import foo as bar, spam as ham searching XXX
      

귀도의 결정

귀도는 상대 임포트가 선행 점(leading dot)을 사용할 것이라고 선언했습니다 [1]. 선행 점이 하나만 있으면 현재 패키지에서 시작하는 상대 임포트를 나타냅니다. 선행 점이 둘 이상이면 현재 패키지의 상위 패키지(들)에 대한 상대 임포트를 나타내며, 첫 번째 점 이후의 점 하나당 한 단계씩 올라갑니다. 다음은 예시 패키지 구조입니다:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

현재 파일이 moduleX.pysubpackage1/__init__.py 중 하나라고 가정하면, 다음은 새 구문의 올바른 사용 예입니다:

from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo
from ...package import bar
from ...sys import path

마지막 경우가 문법적으로는 허용되지만, 확실히 권장되지 않는다는 점에 유의하십시오(“제정신이 아니다”라는 것이 귀도가 사용한 표현이었습니다).

상대 임포트는 항상 from <> import를 사용해야 합니다. import <>는 항상 절대 임포트입니다. 물론 절대 임포트도 선행 점을 생략하면 from <> import를 사용할 수 있습니다. import .foo가 금지된 이유는 다음을 실행한 후에

import XXX.YYY.ZZZ

그러면

XXX.YYY.ZZZ

표현식에서 사용할 수 있기 때문입니다. 하지만

.moduleY

표현식에서 사용할 수 없습니다.

상대 임포트와 __name__

상대 임포트는 모듈의 __name__ 속성을 사용하여 패키지 계층 구조에서 그 모듈의 위치를 결정합니다. 모듈의 이름에 패키지 정보가 전혀 포함되어 있지 않은 경우(예를 들어 ‘__main__’으로 설정된 경우), 상대 임포트는 그 모듈이 실제로 파일 시스템의 어디에 위치하는지와 관계없이 최상위 모듈인 것처럼 해석됩니다.

상대 임포트와 sys.modules의 간접 참조 항목

패키지가 도입되었을 때, sys.modules의 간접 참조 항목이라는 개념이 생겨났습니다 [2]. 패키지 내 모듈에 대한 sys.modules 항목의 값이 None이면, 그 모듈이 실제로는 최상위 모듈을 참조한다는 것을 나타냈습니다. 예를 들어, sys.modules에서 ‘Sound.Effects.string’의 값이 None일 수 있었습니다. 이는 그 이름으로 해석되는 임포트는 실제로는 최상위 ‘string’ 모듈을 임포트하는 것임을 의미했습니다.

이는 상대 임포트가 절대 임포트로 해석되도록 의도된 경우를 위한 최적화를 도입한 것이었습니다. 하지만 이 PEP는 절대 임포트와 상대 임포트를 매우 명확하게 구분하므로, 이 최적화는 더 이상 필요하지 않습니다. 절대/상대 임포트가 유일하게 사용 가능한 임포트 의미 체계가 되면, sys.modules의 간접 참조 항목은 더 이상 지원되지 않을 것입니다.

참고 자료

더 자세한 배경은 다음 python-dev 스레드를 참고하십시오: