문제

다음 디렉터리 구조를 상상해 보세요.

app/
   __init__.py
   sub1/
      __init__.py
      mod1.py
   sub2/
      __init__.py
      mod2.py

코딩 중이에요 mod1, 그리고 다음에서 뭔가를 가져와야 합니다. mod2.어떻게 해야 하나요?

나는 노력했다 from ..sub2 import mod2 하지만 "비패키지에서 상대 가져오기를 시도했습니다"라는 메시지가 나타납니다.

검색해 봤지만 ''만 찾았습니다.sys.path 조작' 해킹.깔끔한 방법 없을까요?


편집하다:나의 모든 __init__.py은(는) 현재 비어 있습니다.

편집2:sub2에는 하위 패키지 간에 공유되는 클래스가 포함되어 있기 때문에 이 작업을 수행하려고 합니다(sub1, subX, 등.).

편집3:내가 찾고 있는 동작은 다음에 설명된 것과 동일합니다. PEP 366 (존 B에게 감사드립니다)

도움이 되었습니까?

해결책

다들 단순히 질문에 답하기보다는 무엇을 해야 하는지 알려주고 싶어하는 것 같습니다.

문제는 mod1.py를 인터프리터에 인수로 전달하여 모듈을 '__main__'으로 실행하고 있다는 것입니다.

에서 PEP 328:

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

Python 2.6에서는 기본 모듈을 기준으로 모듈을 참조하는 기능을 추가하고 있습니다. PEP 366 변경 사항을 설명합니다.

업데이트:Nick Coghlan에 따르면 권장되는 대안은 -m 스위치를 사용하여 패키지 내에서 모듈을 실행하는 것입니다.

다른 팁

main.py
setup.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       module_a.py
    package_b/ ->
       __init__.py
       module_b.py
  1. 당신은 실행 python main.py.
  2. main.py 하다: import app.package_a.module_a
  3. module_a.py 하다 import app.package_b.module_b

또는 2~3명이 다음을 사용할 수 있습니다. from app.package_a import module_a

당신이 가지고 있는 한 그건 효과가 있을 거예요 app 귀하의 PYTHONPATH에서. main.py 그렇다면 어디에나 있을 수 있다.

그래서 당신은 setup.py 전체 앱 패키지와 하위 패키지를 대상 시스템의 Python 폴더에 복사(설치)하고 main.py 대상 시스템의 스크립트 폴더로.

나에게 맞는 솔루션은 다음과 같습니다.

나는 다음과 같이 상대 수입을 수행합니다. from ..sub2 import mod2그리고 내가 달리고 싶다면 mod1.py 그런 다음 상위 디렉토리로 이동합니다. app python -m 스위치를 사용하여 모듈을 실행합니다. python -m app.sub1.mod1.

상대 가져오기에서 이 문제가 발생하는 실제 이유는 상대 가져오기가 __name__ 모듈의 속성입니다.모듈이 직접 실행되는 경우 __name__ 로 설정되어 있습니다 __main__ 패키지 구조에 대한 정보는 포함되어 있지 않습니다.그리고 이것이 Python이 다음에 대해 불평하는 이유입니다. relative import in non-package 오류.

따라서 -m 스위치를 사용하면 Python에 패키지 구조 정보를 제공할 수 있으며 이를 통해 상대 가져오기를 성공적으로 해결할 수 있습니다.

상대 가져오기를 수행하는 동안 이 문제가 여러 번 발생했습니다.그리고 이전 답변을 모두 읽은 후에도 모든 파일에 상용구 코드를 넣을 필요 없이 깔끔한 방법으로 문제를 해결하는 방법을 여전히 알 수 없었습니다.(@ncoghlan 및 @XiongChiamiov 덕분에 일부 댓글이 정말 도움이 되었지만)

PEP를 진행하는 것은 실제로 재미가 없기 때문에 이것이 상대 수입 문제로 싸우는 누군가에게 도움이 되기를 바랍니다.

"Guido는 패키지 내에서 스크립트를 실행하는 것을 안티 패턴으로 간주합니다"(거부됨)PEP-3122)

나는 해결책을 찾기 위해 여기 Stack Overflow에서 관련 게시물을 읽고 "분명 더 나은 방법이 있을 거야!"라고 스스로에게 말하면서 많은 시간을 보냈습니다.없는 것 같습니다.

이 문제는 100% 해결되었습니다:

  • 앱/
    • main.py
  • 설정/
    • local_settings.py

app/main.py에서 settings/local_setting.py를 가져옵니다.

main.py:

import sys
sys.path.insert(0, "../settings")


try:
    from local_settings import *
except ImportError:
    print('No Import')
def import_path(fullpath):
    """ 
    Import a file with full path specification. Allows one to
    import from anywhere, something __import__ does not do. 
    """
    path, filename = os.path.split(fullpath)
    filename, ext = os.path.splitext(filename)
    sys.path.append(path)
    module = __import__(filename)
    reload(module) # Might be out of date
    del sys.path[-1]
    return module

나는 이 조각을 사용하여 경로에서 모듈을 가져오고 있습니다. 도움이 되기를 바랍니다.

설명 nosklo's 예시로 답하다

메모:모두 __init__.py 파일이 비어 있습니다.

main.py
app/ ->
    __init__.py
    package_a/ ->
       __init__.py
       fun_a.py
    package_b/ ->
       __init__.py
       fun_b.py

앱/패키지_a/fun_a.py

def print_a():
    print 'This is a function in dir package_a'

앱/패키지_b/fun_b.py

from app.package_a.fun_a import print_a
def print_b():
    print 'This is a function in dir package_b'
    print 'going to call a function in dir package_a'
    print '-'*30
    print_a()

main.py

from app.package_b import fun_b
fun_b.print_b()

당신이 달리면 $ python main.py 그것은 다음을 반환합니다 :

This is a function in dir package_b
going to call a function in dir package_a
------------------------------
This is a function in dir package_a
  • main.py는 다음을 수행합니다. from app.package_b import fun_b
  • fun_b.py는 그렇습니다 from app.package_a.fun_a import print_a

그래서 폴더에 파일을 package_b 폴더에 사용된 파일 package_a, 그것이 당신이 원하는 것입니다.오른쪽??

이것은 불행하게도 sys.path 해킹이지만 꽤 잘 작동합니다.

다른 레이어에서 이 문제가 발생했습니다.지정된 이름의 모듈이 이미 있지만 잘못된 모듈이었습니다.

내가 하고 싶었던 것은 다음과 같습니다(내가 작업하던 모듈은 module3이었습니다).

mymodule\
   __init__.py
   mymodule1\
      __init__.py
      mymodule1_1
   mymodule2\
      __init__.py
      mymodule2_1


import mymodule.mymodule1.mymodule1_1  

mymodule을 이미 설치했지만 설치에는 "mymodule1"이 없습니다.

설치된 모듈에서 가져오려고 했기 때문에 ImportError가 발생했습니다.

sys.path.append를 시도했지만 작동하지 않았습니다.어떤 일을 했는지 sys.path.insert

if __name__ == '__main__':
    sys.path.insert(0, '../..')

일종의 해킹이지만 모두 작동하게 만들었습니다!따라서 결정을 내리기를 원한다면 명심하십시오. 다른 경로 재정의 그런 다음 sys.path.insert(0, pathname)을 사용하여 작동하게 해야 합니다!이것은 나에게 매우 실망스러운 난제였습니다. 많은 사람들이 sys.path에 "추가" 기능을 사용하라고 말했지만 이미 모듈이 정의되어 있으면 작동하지 않습니다. (매우 이상한 동작이라고 생각합니다.)

제가 참고할 수 있도록 여기에 이 ​​내용을 넣어 보겠습니다.좋은 Python 코드가 아니라는 것을 알고 있지만, 제가 작업하고 있는 프로젝트에 대한 스크립트가 필요했고 그 스크립트를 scripts 예배 규칙서.

import os.path
import sys
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..")))

@EvgeniSergeev가 OP에 대한 설명에서 말했듯이 다음에서 코드를 가져올 수 있습니다. .py 다음을 사용하여 임의의 위치에 파일을 저장합니다.

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

이것은에서 가져온 것입니다 이 SO 답변.

보세요 http://docs.python.org/whatsnew/2.5.html#pep-328-absolute-and-relative-imports.당신은 할 수

from .mod1 import stuff

에서 파이썬 문서,

Python 2.5에서는 다음을 사용하여 가져오기 동작을 절대 가져오기로 전환할 수 있습니다. from __future__ import absolute_import 지령.이 절대 가져오기 동작은 향후 버전(아마도 Python 2.7)에서 기본값이 될 것입니다.일단 절대 수입이 기본값이라면, import string 항상 표준 라이브러리 버전을 찾습니다.사용자는 가능한 한 절대 가져오기를 사용하기 시작하는 것이 좋습니다. 따라서 작성을 시작하는 것이 좋습니다. from pkg import string 귀하의 코드에서

"PYTHONPATH" 환경 변수를 최상위 폴더로 설정하는 것이 더 쉽다는 것을 알았습니다.

bash$ export PYTHONPATH=/PATH/TO/APP

그 다음에:

import sub1.func1
#...more import

물론 PYTHONPATH는 "전역"이지만 아직 문제가 되지는 않았습니다.

John B가 말한 것 외에도 __package__ 변수는 변경하는 대신 도움이 되어야 합니다. __main__ 다른 일을 망칠 수 있습니다.하지만 테스트해 본 결과 제대로 작동하지 않았습니다.

나는 동일한 문제를 겪고 있으며 PEP 328이나 366 모두 문제를 완전히 해결하지 못합니다. 둘 다 결국에는 패키지 헤드가 포함되어야 하기 때문입니다. sys.path, 내가 이해할 수 있는 한.

또한 해당 변수에 들어가야 하는 문자열의 형식을 지정하는 방법을 찾지 못했다는 점도 언급해야 합니다.그렇습니까? "package_head.subfolder.module_name" 또는 무엇을?

최상위 수준에서 실행한 다음 mod1 사용:

import sub2.mod2 

대신에

from ..sub2 import mod2
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top