10 억 시간 동안의 상대적 수입


716

나는 여기에 있었다 :

내가 신속하게 솔루션을 가지고 있다고 생각했을 때 복사하지 않은 많은 URL, 일부는 SO, 일부는 다른 사이트에 있습니다.

영원히 반복되는 질문은 다음과 같습니다. Windows 7, 32 비트 Python 2.7.3에서 "비 패키지에서 상대적인 가져 오기 시도"메시지를 어떻게 해결합니까? pep-0328에서 패키지의 정확한 복제본을 작성했습니다.

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

콘솔에서 가져 오기가 수행되었습니다.

적절한 모듈에서 스팸 및 계란이라는 기능을 만들었습니다. 당연히 작동하지 않았습니다. 대답은 분명히 내가 나열된 네 번째 URL에 있지만 모두 나에게 동문입니다. 내가 방문한 URL 중 하나에이 응답이있었습니다.

상대적 가져 오기는 모듈의 이름 속성을 사용하여 패키지 계층에서 해당 모듈의 위치를 ​​결정합니다. 모듈 이름에 패키지 정보가 포함되어 있지 않은 경우 (예 : 'main'으로 설정) 모듈이 실제로 파일 시스템의 위치에 상관없이 모듈이 최상위 모듈 인 것처럼 상대적 가져 오기가 해결됩니다.

위의 답변은 유망 해 보이지만 모든 상형 문자입니다. 그래서 제 질문은 어떻게 파이썬이 "비 패키지의 상대적인 가져 오기 시도"로 돌아 가지 않게합니까? 아마도 -m과 관련된 대답이 있습니다.

파이썬은 당신이 '패키지'를 정의합니까 왜, 어떻게 "비 패키지", 그리고 무엇을 의미하는지 그 오류 메시지가 제공 왜 누군가가 말해 주시겠습니까 쉽게 충분히 원아가 이해하는 측면에서 정확한 답 넣어 .


5
표시 한 파일을 어떻게 사용하려고합니까? 실행중인 코드는 무엇입니까?
BrenBarn

python.org/dev/peps/pep-0328을 참조하십시오 . 내 게시물에 설명 된 패키지 형식을 사용했습니다. 초기화 평 파일은 비어 있습니다. moduleY.py에는 def spam(): pass, moduleA.py에는 def eggs(): pass있습니다. ".something import something"명령을 실행하려고했지만 작동하지 않았습니다. 다시 한 번, pep-0328을 참조하십시오.

6
내 대답을 참조하십시오. 당신은 여전히 ​​당신이하고있는 일을 완전히 밝히지 않았지만 from .something import something대화 형 통역사에서 하려고하면 작동하지 않습니다. 상대적 가져 오기는 대화식이 아닌 모듈 내에서만 사용할 수 있습니다.
BrenBarn

105
사람들의 "수십억"(이 의견으로는 83,136 명)이이 질문을 검색하기에 수입에 어려움을 겪고 있다는 사실; 파이썬 수입은 대부분의 프로그래머는 아니지만 많은 사람들에게 직관적이지 않다는 결론을 내릴 수 있습니다. 귀도, 아마도 당신은 이것을 받아들이고 수입 메커니즘을 재 설계 할위원회를 요청해야합니다. x.py와 z.py가 동일한 디렉토리에있는 경우이 구문은 최소한 작동해야합니다. 즉, x.py에 "from .z import MyZebraClass"문이있는 경우 x가 main 으로 실행 중이면 x는 z EVEN을 가져와야합니다 ! 왜 그렇게 어려운가요?
Steve L

4
이 스레드의 많은 부분을 읽은 후에는 질문에 대한 대답은 아니지만 "절대 수입 만 사용"이 해결책 인 것 같습니다 ...
CodeJockey

답변:


1042

스크립트 대 모듈

여기에 설명이 있습니다. 짧은 버전은 Python 파일을 직접 실행하는 것과 다른 곳에서 해당 파일을 가져 오는 것 사이에 큰 차이가 있다는 것입니다. 파일이 어떤 디렉토리에 있는지 아는 것만으로도 파이썬이 어떤 패키지에 있다고 생각하는지 결정할 수 없습니다. 또한 파일을 파이썬에로드하는 방법 (실행 또는 가져 오기)에 따라 다릅니다.

Python 파일을로드하는 방법에는 최상위 스크립트 또는 모듈의 두 가지 방법이 있습니다. python myfile.py명령 줄 에 입력하여 파일 을 직접 실행하면 파일이 최상위 스크립트로로드됩니다 . 할 python -m myfile경우 또는 import다른 파일 에서 명령문이 발견 될 때로드되는 경우 모듈 로로드됩니다 . 한 번에 하나의 최상위 스크립트 만있을 수 있습니다. 최상위 스크립트는 작업을 시작하기 위해 실행 한 Python 파일입니다.

명명

파일이로드되면 이름이 부여됩니다 ( __name__속성에 저장 됨 ). 최상위 스크립트로로드 된 경우 이름은 __main__입니다. 모듈로로드 된 경우 해당 이름은 파일 이름이며 그 앞에 부분으로 포함 된 패키지 / 하위 패키지의 이름이 점으로 구분됩니다.

예를 들어 다음과 같습니다.

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

가져온 경우 moduleX(참고 : 직접 실행하지 않고 가져온 ) 이름은입니다 package.subpackage1.moduleX. 가져온 경우 moduleA이름은입니다 package.moduleA. 그러나 명령 행에서 직접 실행 하면 moduleX이름이 대신 __main__이고 moduleA명령 행에서 직접 실행하면 이름은입니다 __main__. 모듈을 최상위 스크립트로 실행하면 일반 이름이 손실되고 대신 이름이 변경됩니다 __main__.

포함 된 패키지를 통하지 않고 모듈에 액세스

추가 주름이 있습니다. 모듈 이름은 모듈이있는 디렉토리에서 "직접"가져 왔는지 또는 패키지를 통해 가져 왔는지에 따라 다릅니다. 디렉토리에서 Python을 실행하고 동일한 디렉토리 (또는 그 서브 디렉토리)에 파일을 가져 오려는 경우에만 차이가 있습니다. 예를 들어, 당신은 디렉토리에 파이썬 인터프리터를 시작하면 package/subpackage1다음 수행 import moduleX의 이름은 moduleX단지 것 moduleX, 그리고 package.subpackage1.moduleX. 파이썬은 시작할 때 현재 디렉토리를 검색 경로에 추가하기 때문입니다. 현재 디렉토리에서 가져올 모듈을 찾으면 해당 디렉토리가 패키지의 일부임을 알 수 없으며 패키지 정보는 모듈 이름의 일부가되지 않습니다.

인터프리터를 대화식으로 실행하는 경우 (예를 들어, python파이썬 코드를 즉시 입력하고 시작하기 만하면) 특별한 경우가 있습니다 . 이 경우 해당 대화식 세션의 이름은입니다 __main__.

이제 오류 메시지의 중요한 사항은 다음과 같습니다 . 모듈 이름에 점이 없으면 패키지의 일부로 간주되지 않습니다 . 파일이 실제로 디스크에있는 위치는 중요하지 않습니다. 중요한 것은 이름이 무엇이며 이름은로드 한 방법에 따라 다릅니다.

이제 질문에 포함 된 인용문을보십시오.

상대적 가져 오기는 모듈의 이름 속성을 사용하여 패키지 계층에서 해당 모듈의 위치를 ​​결정합니다. 모듈 이름에 패키지 정보가 포함되어 있지 않은 경우 (예 : 'main'으로 설정) 모듈이 실제로 파일 시스템의 위치에 상관없이 모듈이 최상위 모듈 인 것처럼 상대적 가져 오기가 해결됩니다.

상대 수입품 ...

상대적 가져 오기는 모듈 이름 을 사용하여 패키지 내 위치를 결정합니다. 와 같은 상대 가져 오기를 사용하는 from .. import foo경우 점은 패키지 계층에서 몇 가지 레벨을 단계적으로 표시합니다. 예를 들어, 현재 모듈의 이름이 package.subpackage1.moduleX인 경우 ..moduleA평균 package.moduleA입니다. A가 들어 from .. import일하기에 있기 때문에, 모듈의 이름은 많은 점으로 최소한 있어야합니다 import문.

... 패키지에서만 상대적

그러나 모듈 이름이 __main__인 경우 패키지에있는 것으로 간주되지 않습니다. 이름에는 점이 없으므로 그 from .. import안에 문을 사용할 수 없습니다 . 이렇게하면 "비 패키지의 상대 가져 오기"오류가 발생합니다.

스크립트는 상대를 가져올 수 없습니다

아마도 당신이 한 일은 moduleX명령 행에서 실행 하는 것입니다. 이 작업을 수행 할 때 이름이로 설정되었습니다 __main__. 즉, 이름이 패키지에 있음을 나타내지 않기 때문에 그 안에있는 상대적 가져 오기에 실패합니다. 모듈이있는 동일한 디렉토리에서 Python을 실행 한 다음 해당 모듈을 가져 오려고 시도하는 경우에도 마찬가지입니다. 위에서 설명한 것처럼 Python은 현재 디렉토리에서 모듈을 인식하지 않고 "너무 일찍"찾을 수 있기 때문입니다. 패키지의 일부.

또한 대화식 인터프리터를 실행할 때 해당 대화식 세션의 "이름"은 항상 __main__입니다. 따라서 대화식 세션에서 직접 상대 가져 오기를 수행 할 수 없습니다 . 상대적 가져 오기는 모듈 파일 내에서만 사용됩니다.

두 가지 솔루션 :

  1. 실제로 moduleX직접 실행 하고 싶지만 여전히 패키지의 일부로 간주하려면을 수행 할 수 있습니다 python -m package.subpackage1.moduleX. 은 -m하지 최상위 스크립트로, 모듈로로드 파이썬을 알려줍니다.

  2. 또는 실제로 실행 하고 싶지 않고 내부 함수 를 사용 하는 moduleX다른 스크립트를 실행하고 싶을 수도 있습니다 . 그런 경우, 넣어 다른 곳 - 하지 내부 디렉토리 -하고 실행합니다. 내부에서 와 같은 작업을 수행하면 제대로 작동합니다.myfile.pymoduleXmyfile.py packagemyfile.pyfrom package.moduleA import spam

노트

  • 이러한 솔루션 중 하나에 대해 패키지 디렉토리 ( package예 :)는 Python 모듈 검색 경로 ( sys.path) 에서 액세스 할 수 있어야합니다 . 그렇지 않으면 패키지의 어떤 것도 안정적으로 사용할 수 없습니다.

  • 파이썬 2.6부터, 패키지 해결을위한 모듈의 "이름"은 __name__속성뿐만 아니라 속성에 의해서도 결정 됩니다 __package__. 그렇기 때문에 __name__모듈의 "이름"을 나타 내기 위해 명시 적 기호 를 사용하지 않는 이유 입니다. 파이썬 2.6 모듈의 "이름"효율적이기 때문에 __package__ + '.' + __name__, 아니면 그냥 __name__경우 __package__입니다 None.)


62
Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.이것은 근본적으로 혼란 스럽습니다. 현재 디렉토리를 보는 것이 어려운 이유는 무엇입니까? 파이썬은 이것을 할 수 있어야합니다. 버전 3x에서 수정 되었습니까?

7
@Stopforgettingmyaccounts ... : PEP 366은 그 작동 방식을 보여줍니다. 파일 안에서는 할 수 있습니다 __package__ = 'package.subpackage1'. 그런 다음 해당 파일이 됩니다 항상 직접 실행할 경우에도 해당 패키지의 일부로 간주한다. 다른 질문이있는 경우 __package__여기에서 원래 질문의 문제를 해결할 때 별도의 질문을 할 수 있습니다.
BrenBarn

108
이것은 모든 Python 상대 수입 질문에 대한 답변이어야합니다. 이것은 문서에도 있어야합니다.
edsioufi 2014 년

10
python.org/dev/peps/pep-0366 참조 - "이 상용구는 sys.path를 통해 최상위 패키지에 이미 액세스 할 수있는 경우에만 충분합니다. 직접 실행을 위해서는 sys.path를 조작하는 추가 코드가 필요합니다. 최상위 패키지를 이미 가져올 수없는 상태에서 작동합니다. " -이 "추가 코드"는 실제로 상당히 길고 패키지의 다른 곳에 저장하여 쉽게 실행할 수 없기 때문에 이것은 나에게 가장 혼란스러운 비트입니다.
마이클 스캇 커스버트

14
이 답변은 현재 __name__및 에 관한 몇 가지 중요한 세부 정보를 제공하지 않습니다 sys.path. 구체적으로 python -m pkg.mod,이 __name__로 설정 __main__하지 pkg.mod; 이 경우가 __package__아닌 상대 수입이 해결됩니다 __name__. 또한 파이썬은 sys.path실행할 때 현재 디렉토리가 아닌 스크립트의 디렉토리를 추가합니다 python path/to/script.py. 를 sys.path포함하여 대부분의 다른 방법을 실행할 때 현재 디렉토리를 추가합니다 python -m pkg.mod.
user2357112는

42

이것은 실제로 파이썬 내에서 문제입니다. 혼란의 기원은 사람들이 실수를 상대 경로를 경로 상대 경로로 잘못 가져 간다는 것입니다.

예를 들어 faa.py로 쓸 때 :

from .. import foo

이것은 실행 중에 패키지의 일부로 python에서 faa.py식별하고로드 한 경우에만 의미 가 있습니다. 이 경우, 모듈의 이름 에 대한 faa.py는 예를 들어이 될 것 some_packagename.faa . 파일이 현재 디렉토리에 있기 때문에 파일이로드 된 경우, 파이썬이 실행될 때 파일 이름은 패키지를 참조하지 않으며 결국 상대 가져 오기가 실패합니다.

현재 디렉토리에서 모듈을 참조하는 간단한 해결책은 다음을 사용하는 것입니다.

if __package__ is None or __package__ == '':
    # uses current directory visibility
    import foo
else:
    # uses current package visibility
    from . import foo

5
올바른 해결책은 from __future__ import absolute_import사용자가 코드를 올바르게 사용하도록 강요하는 것입니다. 항상 가능합니다from . import foo
Giacomo Alzetta

@Giacomo : 내 문제에 대한 절대적으로 정답입니다. 감사!
Fábio

8

다음은 예제로 적합하도록 수정 된 일반적인 레시피입니다. 패키지로 작성된 Python 라이브러리를 처리하기 위해 현재 사용하고 있으며, 상호 의존적 인 파일이 포함되어 있으며, 일부는 부분적으로 테스트 할 수 있습니다. 의이 부르 자 lib.foo하고 액세스해야한다고 말하는 lib.fileA기능 f1f2, 및 lib.fileB클래스를 Class3.

print이것이 어떻게 작동하는지 설명하기 위해 몇 가지 전화를 포함 시켰습니다 . 실제로 당신은 그것들을 제거하고 싶을 것 from __future__ import print_function입니다.

이 특정 예제는에 항목을 실제로 삽입해야 할 때 표시하기에는 너무 단순합니다 sys.path. (참조 라스 '대답은 우리가 경우에 우리가 패키지 디렉토리의 두 개 이상의 수준을 가지고 있고, 우리가 사용하는 경우, 필요 os.path.dirname(os.path.dirname(__file__))정말하지 않습니다 -하지만 상처 중 여기가.) 그것은없이이 작업을 수행하는 안전 충분한이기도 if _i in sys.path테스트. 그러나 각 가져온 파일을 삽입하는 경우 동일한 경로에 대한 예, 두 경우 fileA와는 fileB패키지-이 클러부터 임포트 유틸리티에 원하는 sys.path그것의 좋은이 가지고있는 동일한 경로 많은 시간이, 그래서 if _i not in sys.path상용구에 있습니다.

from __future__ import print_function # only when showing how this works

if __package__:
    print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
    from .fileA import f1, f2
    from .fileB import Class3
else:
    print('Not a package; __name__ is {!r}'.format(__name__))
    # these next steps should be used only with care and if needed
    # (remove the sys.path manipulation for simple cases!)
    import os, sys
    _i = os.path.dirname(os.path.abspath(__file__))
    if _i not in sys.path:
        print('inserting {!r} into sys.path'.format(_i))
        sys.path.insert(0, _i)
    else:
        print('{!r} is already in sys.path'.format(_i))
    del _i # clean up global name space

    from fileA import f1, f2
    from fileB import Class3

... all the code as usual ...

if __name__ == '__main__':
    import doctest, sys
    ret = doctest.testmod()
    sys.exit(0 if ret.failed == 0 else 1)

여기 아이디어는 이것입니다 (그리고 이것들은 모두 python2.7과 python 3.x에서 동일하게 작동합니다).

  1. 일반 코드에서 import lib또는 from lib import foo일반 패키지로 일반 패키지 가져 오기로 실행하면 __packageis liband __name__is lib.foo입니다. 에서 가져 오는 첫 번째 코드 경로 .fileA를 사용합니다.

  2. 로 실행하면 python lib/foo.py, __package__아무도 없을 것입니다 __name__될 것입니다 __main__.

    우리는 두 번째 코드 경로를 사용합니다. lib디렉토리가 이미있는 것입니다 sys.path추가 할 필요가 없습니다 그래서. fileA등에서 수입

  3. lib디렉토리 내에서 실행될 경우 python foo.py동작은 사례 2와 동일합니다.

  4. lib디렉토리 내에서 실행되는 경우 python -m foo동작은 사례 2 및 3과 유사합니다. 그러나 lib디렉토리 경로 가에 있지 않으므로 sys.path가져 오기 전에 추가합니다. Python을 실행 한 다음에도 마찬가지 import foo입니다.

    이후 ( . sys.path, 우리는 정말 여기에 경로의 절대 버전을 추가 할 필요가 없습니다. 우리가 원하는 깊은 패키지 중첩 구조는 곳입니다 from ..otherlib.fileC import ..., 차이가 있습니다. 당신이이 일을하지 않는 경우, 당신은 할 수 있습니다 모든 sys.path조작을 완전히 생략하십시오 .)

노트

여전히 기발한 것이 있습니다. 이 모든 것을 외부에서 실행하면 :

$ python2 lib.foo

또는:

$ python3 lib.foo

동작은의 내용에 따라 다릅니다 lib/__init__.py. 그것이 존재하고 비어 있으면 모든 것이 잘됩니다.

Package named 'lib'; __name__ is '__main__'

그러나 lib/__init__.py 자체로 가져 routine와서 routine.name직접 (으)로 내보낼 수 있다면 lib.name다음을 얻을 수 있습니다.

$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'

즉, 패키지를 통해 한 번 모듈을 두 번 가져온 다음 코드를 __main__실행하도록 다시 가져옵니다 main. 파이썬 3.6 이상은 이것에 대해 경고합니다 :

$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'

경고는 새로운이지만, 경고-에 대해 동작하지 않습니다. 일부 는 이중 가져 오기 트랩 이라고 하는 것의 일부 입니다. (자세한 내용은 이슈 27487을 참조하십시오 .) Nick Coghlan의 말 :

이 다음 트랩은 3.3을 포함한 모든 현재 버전의 Python에 존재하며 다음 일반 지침에 요약 할 수 있습니다. "패키지 디렉토리 또는 패키지 내의 디렉토리를 Python 경로에 직접 추가하지 마십시오".

여기서 규칙을 위반하는 동안 로드되는 파일이 패키지의 일부로로드 되지 않는 경우 에만 해당 규칙이 적용 되며 수정 사항은 해당 패키지의 다른 파일에 액세스 할 수 있도록 특별히 설계되었습니다. (그리고 내가 언급했듯이, 우리는 아마 단일 레벨 패키지에 대해 이것을해서는 안됩니다.) 우리가 깨끗하게하고 싶다면 다음과 같이 다시 작성할 수 있습니다.

    import os, sys
    _i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    if _i not in sys.path:
        sys.path.insert(0, _i)
    else:
        _i = None

    from sub.fileA import f1, f2
    from sub.fileB import Class3

    if _i:
        sys.path.remove(_i)
    del _i

즉, sys.path가져 오기를 수행 할 수있을 정도로 오래 수정 한 다음 원래 상태로 되돌립니다 ( _iif의 사본 하나만 추가 한 경우에만 사본 하나 삭제 _i).


7

그래서 다른 많은 사람들과 함께이 문제를 해결 한 후이 기사 에서 Dorian B 가 게시 한 메모를 보았습니다 . 웹 서비스와 함께 사용할 모듈과 클래스를 개발할 때 발생하는 특정 문제를 해결했지만 PyCharm의 디버거 기능을 사용하여 코딩 할 때 테스트 할 수 있습니다. 독립적 인 클래스에서 테스트를 실행하려면 클래스 파일 끝에 다음을 포함시킵니다.

if __name__ == '__main__':
   # run test code here...

그러나 같은 폴더에 다른 클래스 또는 모듈을 가져 오려면 모든 가져 오기 문을 상대 표기법에서 로컬 참조로 변경해야합니다 (예 : 점 (.) 제거). 그러나 Dorian의 제안을 읽은 후 ' 하나의 라이너와 작동했습니다! 이제 PyCharm에서 테스트하고 테스트중인 다른 클래스에서 클래스를 사용하거나 웹 서비스에서 사용할 때 테스트 코드를 그대로 둘 수 있습니다!

# import any site-lib modules first, then...
import sys
parent_module = sys.modules['.'.join(__name__.split('.')[:-1]) or '__main__']
if __name__ == '__main__' or parent_module.__name__ == '__main__':
    from codex import Codex # these are in same folder as module under test!
    from dblogger import DbLogger
else:
    from .codex import Codex
    from .dblogger import DbLogger

문 검사는 우리가이 모듈을 실행하는 경우 참조하는 경우 또는 그것으로 테스트되고있어 다른 모듈에 사용되고있는 경우 . 아마도 이것은 명백하지만, 위의 상대적인 수입 문제로 좌절 한 다른 사람이 그것을 사용할 수있는 경우에 대비 하여이 메모를 제공합니다.


1
실제로 해결됩니다. 그러나 정말 불쾌합니다. 이것이 기본 동작이 아닌 이유는 무엇입니까?!
lo tolmencre

4

다음은 권장하지 않지만 모듈이 단순히 생성되지 않은 일부 상황에서 유용 할 수있는 솔루션입니다.

import os
import sys
parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(parent_dir_name + "/your_dir")
import your_script
your_script.a_function()

2

파이썬 모듈 검색 경로를 변경하고 싶지 않고 스크립트에서 모듈을 상대적으로로드 해야하는 비슷한 문제가 발생했습니다 ( "스크립트는 모두를 상대로 가져올 수는 없지만") BrenBarn이 위에서 설명한 것처럼 ).

그래서 나는 다음과 같은 핵을 사용했습니다. 불행히도, 그것은 imp버전 3.4 이후에 더 이상 사용되지 않는 모듈 에 의존하여 삭제되었습니다 importlib. (이것도 가능 importlib합니까? 모르겠습니다.) 아직도 해킹은 작동합니다.

의 구성원에 액세스하기위한 예 moduleX에서을 subpackage1에 거주하는 스크립트에서 subpackage2폴더 :

#!/usr/bin/env python3

import inspect
import imp
import os

def get_script_dir(follow_symlinks=True):
    """
    Return directory of code defining this very function.
    Should work from a module as well as from a script.
    """
    script_path = inspect.getabsfile(get_script_dir)
    if follow_symlinks:
        script_path = os.path.realpath(script_path)
    return os.path.dirname(script_path)

# loading the module (hack, relying on deprecated imp-module)
PARENT_PATH = os.path.dirname(get_script_dir())
(x_file, x_path, x_desc) = imp.find_module('moduleX', [PARENT_PATH+'/'+'subpackage1'])
module_x = imp.load_module('subpackage1.moduleX', x_file, x_path, x_desc)

# importing a function and a value
function = module_x.my_function
VALUE = module_x.MY_CONST

더 깔끔한 접근법은 Federico가 언급 한대로 모듈을로드하는 데 사용되는 sys.path를 수정하는 것 같습니다.

#!/usr/bin/env python3

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    # __file__ should be defined in this case
    PARENT_DIR = path.dirname(path.dirname(path.abspath(__file__)))
   sys.path.append(PARENT_DIR)
from subpackage1.moduleX import *

그것은 더 나아 보입니다 ... 너무 나빠 여전히 파일에 부모 디렉토리의 이름을 포함시켜야합니다 ... 아마도 importlib로 향상 될 수 있습니다. 아마도 importlib은 간단한 사용 사례를 위해 상대적인 가져 오기를 "작동하는"것으로 만들기 위해 몽키 패치 될 수도 있습니다. 나는 그것에 금이 갈 것이다.
앤드류 바그너

파이썬 2.7.14를 사용하고 있습니다. 이런 식으로 여전히 작동합니까?
user3474042

방금 파이썬 2.7.10에 대한 두 가지 접근법을 모두 테스트했으며 제대로 작동했습니다. 사실 2.7에서 더 이상 사용되지 않는 imp 모듈에 문제가 없으므로 더 좋습니다.
Lars

2

__name__ 문제의 코드가 전역 네임 스페이스에서 실행되는지 아니면 가져온 모듈의 일부로 실행되는지에 따라 변경됩니다.

코드가 전역 공간에서 실행되고 있지 않으면 __name__모듈 이름이됩니다. 전역 네임 스페이스에서 실행중인 경우 (예 : 콘솔에 입력하거나 python.exe yourscriptnamehere.py다음을 사용하여 스크립트로 모듈을 실행하는 경우) __name__가됩니다 "__main__".

if __name__ == '__main__'코드가 전역 네임 스페이스에서 실행되고 있는지 테스트하는 데 사용되는 많은 Python 코드 가 있습니다.이를 통해 스크립트의 두 배인 모듈을 가질 수 있습니다.

콘솔에서 가져 오기를 시도 했습니까?


아, -m을 언급했습니다. 그러면 모듈로 스크립트가 실행됩니다. if __name__ == '__main__'을 고정하면 -m 때문에 '__main__'이라는 것을 알 수 있습니다. 이 최고 수준이되지 않도록 또 다른 모듈에 모듈을 가져보십시오 ... 그건 당신이 상대적으로 수입 할 수 있도록해야한다
theodox

콘솔에서 가져 오기를 시도했지만 활성 파일이 올바른 모듈입니다.

@Stopforgettingmyaccounts ... : "활성 파일"은 무엇을 의미합니까?
BrenBarn

나는 Pyscripter를 사용합니다. from .moduleY import spam from 에서 이러한 가져 오기를 실행할 때 moduleX.py에있었습니다 . 수입 모듈 Y.

.moduleY 다음에 moduleY.spam ()을 가져 오지 않습니까?
theodox

2

@BrenBarn의 답변에 모든 내용이 나와 있지만 나와 같다면 이해하는 데 시간이 걸릴 수 있습니다. 여기 내 사건과 @BrenBarn의 답변이 어떻게 적용되는지, 아마도 도움이 될 것입니다.

경우

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

익숙한 예제를 사용하여 moduleX.py가 ..moduleA 로의 상대적 가져 오기를 추가하십시오. moduleX를 가져온 subpackage1 디렉토리에 테스트 스크립트를 작성하려고 시도했지만 OP에서 설명하는 두려운 오류가 발생했습니다.

해결책

테스트 스크립트를 패키지와 동일한 레벨로 이동하고 package.subpackage1.moduleX를 가져 오십시오.

설명

설명한 바와 같이, 상대적 가져 오기는 현재 이름을 기준으로 이루어집니다. 테스트 스크립트가 같은 디렉토리에서 moduleX를 가져올 때 moduleX 내의 모듈 이름은 moduleX입니다. 상대 가져 오기가 발생하면 인터프리터는 이미 최상위에 있으므로 패키지 계층 구조를 백업 할 수 없습니다.

위에서 moduleX를 가져올 때 moduleX 내부의 이름은 package.subpackage1.moduleX이며 상대 가져 오기를 찾을 수 있습니다


당신이 나를 안내 할 수 있기를 바랍니다. 다음 링크에서 사례 3으로 이동하면 솔루션 1을 사용할 수 없습니다. 이것을 확인하고 알려주십시오. 그것은 엄청나게 도움이 될 것입니다. chrisyeh96.github.io/2017/08/08/…
변수

@variable 링크에 오타가 있으며 편집 할 수 없습니다. 사례 3을 살펴본 결과 정확히 파악하지 못했습니다. 파이썬 2에서 그 예를 시도했을 때 문제가 없었기 때문에 내가 놓친 것으로 생각합니다. 새로운 질문을 게시해야하지만보다 명확한 예를 제공해야 할 수도 있습니다. 사례 4는 내 대답에서 내가 말하는 것에 대해 이야기합니다. 통역사가 부모 디렉토리에서 시작하지 않는 한 상대 가져 오기 디렉토리를 올라갈 수 없습니다
Brad Dre

고맙습니다. 저는 파이썬 3과 여기에서 stackoverflow.com/questions/58577767/…
변수

1

상대적 가져 오기는 모듈의 이름 속성을 사용하여 패키지 계층에서 해당 모듈의 위치를 ​​결정합니다. 모듈 이름에 패키지 정보가 포함되어 있지 않은 경우 (예 : 'main'으로 설정) 모듈이 실제로 파일 시스템의 위치에 상관없이 모듈이 최상위 모듈 인 것처럼 상대적 가져 오기가 해결됩니다.

이 질문의 시청자를 도울 수있는 작은 파이썬 패키지를 PyPi에 썼습니다. 가져 오기 파일의 디렉토리에 직접 있지 않고 패키지 / 프로젝트 내에서 상위 레벨 패키지를 포함하는 가져 오기가 포함 된 Python 파일을 실행하려는 경우 패키지가 임시 해결책으로 작동합니다. https://pypi.org/project/import-anywhere/


-2

파이썬이 저에게 "비 패키지의 상대적인 가져 오기 시도"로 돌아 가지 않게하기 위해. 꾸러미/

init .py subpackage1 / init .py moduleX.py moduleY.py subpackage2 / init .py moduleZ.py moduleA.py

이 오류는 상대 파일을 상위 파일에 적용하는 경우에만 발생합니다. 예를 들어 moduleA.py에서 "print ( name )" 을 코딩 한 후 부모 파일은 이미 main 을 반환합니다 . 따라서이 파일은 이미 main입니다더 이상 상위 패키지를 반환 할 수 없습니다. 패키지 subpackage1 및 subpackage2의 파일에서 상대 가져 오기가 필요합니다. ".."를 사용하여 상위 디렉토리 또는 모듈을 참조 할 수 있습니다. 그러나 상위 패키지가 이미 상위 레벨 인 경우 상위 디렉토리 (패키지)보다 더 상위 레벨로 이동할 수 없습니다. 부모에게 상대적인 가져 오기를 적용하는 이러한 파일은 절대 가져 오기의 적용으로 만 작동 할 수 있습니다. 부모 패키지에서 절대 수입을 사용하면 프로젝트의 최상위 레벨을 정의하는 PYTHON PATH 개념으로 인해 파일이 하위 패키지에 있더라도 파이썬이 누가 패키지의 최상위 레벨에 있는지 알기 때문에 오류가 발생하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.