파이썬 3의 상대적 수입


712

같은 디렉토리의 다른 파일에서 함수를 가져오고 싶습니다.

때때로 그것은 나를 위해 작동 from .mymodule import myfunction하지만 때로는 나는 :

SystemError: Parent module '' not loaded, cannot perform relative import

때로는 작동 from mymodule import myfunction하지만 때로는 다음 과 같은 결과가 나타납니다.

SystemError: Parent module '' not loaded, cannot perform relative import

나는 여기의 논리를 이해하지 못했고 설명을 찾을 수 없었습니다. 이것은 완전히 무작위로 보입니다.

누군가이 모든 것에 대한 논리가 무엇인지 설명해 줄 수 있습니까?


76
이는 패키지 내에서 모듈로 스크립트를 실행하고 있음을 의미합니다. 패키지 외부 에서만 스크립트를 실행 하십시오.
Martijn Pieters

3
아마도 당신은 당신이 언급 한 '때때로'가지고있는 조건을 정의해야합니다. 나는 당신이 무작위 오류가 있다는 것을 의미하지는 않는다는 것을 이해합니다.
joaquin 2016 년

15
@MartijnPieters : 불행히도이 모듈은 패키지 안에 있어야하며, 때로는 스크립트로 실행할 수도 있어야합니다. 내가 어떻게 그것을 달성 할 수 있는지 아는가?
존 스미스 옵션

22
@JohnSmithOptional : 패키지 내에서 스크립트를 혼합하는 것은 까다 롭고 가능하면 피해야합니다. 패키지를 가져오고 대신 '스크립트'기능을 실행하는 래퍼 스크립트를 사용하십시오.
Martijn Pieters

3
불행한 것 같습니다. 특정 종류의 파일을 구문 분석 / 분석 할 수있는 클래스 / 메서드가있는 핵심 모듈을 만들었으며,이 모듈을 가져 오는 별도의 보조 모듈 및 스크립트도 있습니다 (이 파일을 마사지 / 변환 할 수 있음). 그러나 단일 코어 파일 (전체 복잡한 패키지는 아님)을 최종 사용자에게 전달하여 파일 옆에 쉽게 놓고 실행할 수 있기를 원합니다. 이 "스크립트 모드"에서는 파일과 인코딩을 구문 분석 및 분석하고 다양한 필드 / 값 / 특수 문자를 계산하여 보고서를 제공합니다. 그러나 실제로 파일을 수정하지는 않습니다. 안티 패턴?
Jon Coombs

답변:


526

불행히도이 모듈은 패키지 안에 있어야하며, 때로는 스크립트로 실행할 수도 있어야합니다. 내가 어떻게 그것을 달성 할 수 있는지 아는가?

이와 같은 레이아웃을 갖는 것이 일반적입니다 ...

main.py
mypackage/
    __init__.py
    mymodule.py
    myothermodule.py

... mymodule.py이와 같이 ...

#!/usr/bin/env python3

# Exported function
def as_int(a):
    return int(a)

# Test function for module  
def _test():
    assert as_int('1') == 1

if __name__ == '__main__':
    _test()

... myothermodule.py이런 ...

#!/usr/bin/env python3

from .mymodule import as_int

# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

... 그리고 main.py이것처럼 ...

#!/usr/bin/env python3

from mypackage.myothermodule import add

def main():
    print(add('1', '1'))

if __name__ == '__main__':
    main()

... 당신이 실행할 때 잘 작동하는 main.pymypackage/mymodule.py,하지만 실패 mypackage/myothermodule.py로 인해 상대적 가져 오기에 ...

from .mymodule import as_int

당신이 그것을 실행하는 방식은 ...

python3 -m mypackage.myothermodule

... 그러나 다소 장황하고 같은 shebang 라인과 잘 섞이지 않습니다 #!/usr/bin/env python3.

이름 mymodule이 전역 적으로 고유 하다고 가정하면이 경우 가장 간단한 수정은 상대 가져 오기 사용을 피하고 그냥 사용하는 것입니다 ...

from mymodule import as_int

... 독특하지 않거나 패키지 구조가 더 복잡한 경우에는 패키지 디렉토리가 포함 된 디렉토리를에 포함시켜야합니다 PYTHONPATH.

from mypackage.mymodule import as_int

... 또는 "즉시"작동하도록하려면 PYTHONPATH먼저 코드에서 코드를 제거 할 수 있습니다 .

import sys
import os

PACKAGE_PARENT = '..'
SCRIPT_DIR = os.path.dirname(os.path.realpath(os.path.join(os.getcwd(), os.path.expanduser(__file__))))
sys.path.append(os.path.normpath(os.path.join(SCRIPT_DIR, PACKAGE_PARENT)))

from mypackage.mymodule import as_int

그것은 일종의 고통이지만 , 특정 Guido van Rossum이 작성한 이메일 에 왜 단서가 있습니다 ...

나는 이것과 다른 제안 된 __main__ 기계류 에 -1입니다 . 유일한 유스 케이스는 모듈의 디렉토리 안에있는 스크립트를 실행하는 것 같습니다. 항상 반 패턴으로 보았습니다. 내 마음을 바꾸게하려면 그렇지 않다는 것을 저에게 납득시켜야합니다.

패키지 내에서 스크립트를 실행하는 것이 반 패턴인지 아닌지는 주관적이지만 개인적으로 일부 사용자 정의 wxPython 위젯을 포함하는 패키지에서 실제로 유용하다는 것을 알았습니다. 따라서 소스 파일 중 하나에 대해 스크립트를 실행하여 wx.Frame포함 만 표시 할 수 있습니다 테스트 목적으로 해당 위젯.


7
SCRIPTDIR를 얻을 수있는 더 좋은 방법이 주어진다 상대 경로에서 가져 오기 모듈의 코멘트os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))모듈은 항상 가지고 적절한 것을 당신 자신이 경우 file당신은 또한 사용할 수 있습니다 os.path.realpath(os.path.dirname(__file__)).
marcz

2
당신은 더 짧고 읽을 수있는 코드 적용하여 PYTHONPATH를 확장 할 수 있습니다 : sys.path.append( os.path.join( os.path.dirname(__file__), os.path.pardir ) )
알렉스 - 보그

12
...which I've always seen as an antipattern.안티 패턴이 어떻게 보이는지 모르겠습니다 ... 단순히 상대 수입품을 직관적으로 작동시키는 것이 매우 편리합니다. 나는 내가 알고있는 것을 같은 디렉토리에 가져올 수 있기를 원합니다. 그의 추론이 무엇인지 궁금하다
YungGun

9
귀도는 또 다시 파업했다. 더 이상 그런 일은 일어나지 않을 것입니다.
javadba

4
이것은 내가 파이썬에 대해 본 것 중 가장 슬프다.
AtilioA

262

설명

에서 PEP (328)

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

어느 시점에서 PEP 338PEP 328 과 충돌했습니다 .

... 상대적 가져 오기는 __name__ 을 사용하여 패키지 계층에서 현재 모듈의 위치를 ​​결정합니다. 기본 모듈에서 __name__ 의 값 은 항상 '__main__'입니다. 이므로 명시 적 상대 가져 오기는 항상 실패합니다 (패키지 내의 모듈에 대해서만 작동하므로)

이 문제를 해결하기 위해 PEP 366 은 최상위 변수를 도입했습니다 __package__.

새로운 모듈 레벨 속성을 추가하여이 PEP를 사용하면 -m 스위치를 사용하여 모듈을 실행할 경우 상대 가져 오기가 자동으로 작동 합니다. 모듈 자체에 소량의 상용구가 있으면 파일을 이름으로 실행할 때 상대 가져 오기가 작동합니다. [...] [속성]이 있으면 상대 가져 오기는 모듈 __name__ 속성이 아니라이 속성을 기반으로 합니다. [...] 메인 모듈이 파일 이름으로 지정되면 __package__ 속성이 None 으로 설정됩니다 . [...] 가져 오기 시스템에서 __package__가 설정되지 않은 (또는 None으로 설정된) 모듈에서 명시 적 상대 가져 오기가 발생하면 올바른 값을 계산하여 저장합니다 (일반 모듈의 경우 __name __. rpartition ( '.') [0] 및 패키지 초기화 모듈의 경우 __name__ )

(강조 광산)

(가) 경우 __name__이며 '__main__', __name__.rpartition('.')[0]빈 문자열을 반환합니다. 이것이 오류 설명에 빈 문자열 리터럴이있는 이유입니다.

SystemError: Parent module '' not loaded, cannot perform relative import

CPython PyImport_ImportModuleLevelObject함수 의 관련 부분 :

if (PyDict_GetItem(interp->modules, package) == NULL) {
    PyErr_Format(PyExc_SystemError,
            "Parent module %R not loaded, cannot perform relative "
            "import", package);
    goto error;
}

CPython은 (로 액세스 가능 package)에서 interp->modules( 패키지 이름) 을 찾을 수없는 경우이 예외를 발생 sys.modules시킵니다. 이후 sys.modules입니다 "이미로드 된 모듈에 모듈 이름을 매핑하는 사전" , 이제 것이 분명 부모 모듈이 명시 적으로 상대 가져 오기를 수행하기 전에-절대 가져와야합니다 .

참고 로부터 패치 문제 18018은 추가 한 다른 if블록 이 실행되고, 이전 코드 위 :

if (PyUnicode_CompareWithASCIIString(package, "") == 0) {
    PyErr_SetString(PyExc_ImportError,
            "attempted relative import with no known parent package");
    goto error;
} /* else if (PyDict_GetItem(interp->modules, package) == NULL) {
    ...
*/

경우 package(위와 동일)이 빈 문자열, 오류 메시지가 될 것입니다

ImportError: attempted relative import with no known parent package

그러나 Python 3.6 이상에서만 이것을 볼 수 있습니다.

해결 방법 # 1 : -m을 사용하여 스크립트 실행

디렉토리 (Python 패키지 ) 를 고려하십시오 .

.
├── package
│   ├── __init__.py
│   ├── module.py
│   └── standalone.py

패키지의 모든 파일 은 동일한 두 줄의 코드로 시작합니다.

from pathlib import Path
print('Running' if __name__ == '__main__' else 'Importing', Path(__file__).resolve())

나는이 두 줄을 포함하고 있습니다 분명 작업의 순서를 확인합니다. 실행에 영향을 미치지 않으므로 완전히 무시할 수 있습니다.

__init__.pymodule.py 에는 두 줄만 포함됩니다 (즉, 실제로 비어 있음).

standalone.py는 추가 로 상대 가져 오기를 통해 module.py 를 가져 오려고 시도합니다 .

from . import module  # explicit relative import

우리는 그것이 /path/to/python/interpreter package/standalone.py실패 할 것이라는 것을 잘 알고 있습니다. 그러나, 우리가 가진 모듈을 실행할 수있는 -m명령 줄 옵션 것이다 "검색 sys.path명명 된 모듈과 같은 내용을 실행 __main__모듈을" :

vaultah@base:~$ python3 -i -m package.standalone
Importing /home/vaultah/package/__init__.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/module.py
>>> __file__
'/home/vaultah/package/standalone.py'
>>> __package__
'package'
>>> # The __package__ has been correctly set and module.py has been imported.
... # What's inside sys.modules?
... import sys
>>> sys.modules['__main__']
<module 'package.standalone' from '/home/vaultah/package/standalone.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>

-m 모든 가져 오기 작업을 수행하고 자동으로 설정합니다. __package__ 하지만

해결 방법 # 2 : __package__를 수동으로 설정

실제 솔루션이 아닌 개념 증명으로 취급하십시오. 실제 코드에서 사용하기에 적합하지 않습니다.

PEP 366 은이 문제에 대한 해결 방법이 있지만 설정 __package__만으로는 충분하지 않으므로 불완전 합니다. 모듈 계층 구조에서 N 개 이상의 선행 패키지 를 가져와야 합니다. 여기서 N 은 가져올 모듈을 검색 할 상위 디렉토리 (스크립트의 디렉토리에 해당)의 수입니다.

그러므로,

  1. 현재 모듈 의 N 번째 선행 작업의 상위 디렉토리를 추가하십시오.sys.path

  2. 에서 현재 파일의 디렉토리를 제거하십시오 sys.path

  3. 정규화 된 이름을 사용하여 현재 모듈의 상위 모듈을 가져옵니다.

  4. 2__package__ 에서 정규화 된 이름으로 설정

  5. 상대적 가져 오기 수행

솔루션 # 1 에서 파일을 빌리고 더 많은 하위 패키지를 추가합니다.

package
├── __init__.py
├── module.py
└── subpackage
    ├── __init__.py
    └── subsubpackage
        ├── __init__.py
        └── standalone.py

이번에는 standalone.py 는 다음과 같은 상대 가져 오기를 사용하여 패키지 패키지 에서 module.py 를 가져옵니다.

from ... import module  # N = 3

그 줄 앞에 상용구 코드를 붙여서 작동시켜야합니다.

import sys
from pathlib import Path

if __name__ == '__main__' and __package__ is None:
    file = Path(__file__).resolve()
    parent, top = file.parent, file.parents[3]

    sys.path.append(str(top))
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass

    import package.subpackage.subsubpackage
    __package__ = 'package.subpackage.subsubpackage'

from ... import module # N = 3

파일 이름으로 standalone.py 를 실행할 수 있습니다 .

vaultah@base:~$ python3 package/subpackage/subsubpackage/standalone.py
Running /home/vaultah/package/subpackage/subsubpackage/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/subpackage/__init__.py
Importing /home/vaultah/package/subpackage/subsubpackage/__init__.py
Importing /home/vaultah/package/module.py

함수에 싸여진보다 일반적인 해결책은 여기 에서 찾을 수 있습니다 . 사용법 예 :

if __name__ == '__main__' and __package__ is None:
    import_parents(level=3) # N = 3

from ... import module
from ...module.submodule import thing

해결 방법 # 3 : 절대 가져 오기 및 설정 도구 사용

단계는-

  1. 명시 적 상대 수입을 동등한 절대 수입으로 교체

  2. package가져 오기 가능하도록 설치

예를 들어, 디렉토리 구조는 다음과 같습니다.

.
├── project
│   ├── package
│   │   ├── __init__.py
│   │   ├── module.py
│   │   └── standalone.py
│   └── setup.py

어디 setup.py가 있다

from setuptools import setup, find_packages
setup(
    name = 'your_package_name',
    packages = find_packages(),
)

나머지 파일은 솔루션 # 1 에서 빌 렸습니다 .

설치하면 작업 디렉토리에 관계없이 패키지를 가져올 수 있습니다 (이름 지정 문제가 없다고 가정).

이 장점을 사용하기 위해 standalone.py 를 수정할 수 있습니다 (1 단계).

from package import module  # absolute import

에 작업 디렉토리로 변경 project하고 실행 /path/to/python/interpreter setup.py install --user( --user에서 패키지를 설치 하여 사이트 패키지 디렉토리 ) (2 단계) :

vaultah@base:~$ cd project
vaultah@base:~/project$ python3 setup.py install --user

standalone.py 를 스크립트 로 실행할 수 있는지 확인하십시오 :

vaultah@base:~/project$ python3 -i package/standalone.py
Running /home/vaultah/project/package/standalone.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py
Importing /home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/.local/lib/python3.6/site-packages/your_package_name-0.0.0-py3.6.egg/package/module.py'>

참고 :이 경로를 사용하기로 결정한 경우 가상 환경 을사용하여패키지를 별도로 설치하는 것이 좋습니다.

해결책 # 4 : 절대 수입품과 일부 상용구 코드 사용

솔직히 설치가 필요하지 않습니다. 스크립트 파일에 상용구 코드를 추가하여 절대적으로 가져올 수 있습니다.

솔루션 # 1 에서 파일을 빌리고 standalone.py를 변경 하겠습니다 .

  1. 의 상위 디렉토리 추가 패키지sys.path 전에 에서 아무것도 가져 오려고 패키지 절대 수입을 사용하여 :

    import sys
    from pathlib import Path # if you haven't already done so
    file = Path(__file__).resolve()
    parent, root = file.parent, file.parents[1]
    sys.path.append(str(root))
    
    # Additionally remove the current file's directory from sys.path
    try:
        sys.path.remove(str(parent))
    except ValueError: # Already removed
        pass
  2. 상대 가져 오기를 절대 가져 오기로 바꾸십시오.

    from package import module  # absolute import

standalone.py 는 문제없이 됩니다.

vaultah@base:~$ python3 -i package/standalone.py
Running /home/vaultah/package/standalone.py
Importing /home/vaultah/package/__init__.py
Importing /home/vaultah/package/module.py
>>> module
<module 'package.module' from '/home/vaultah/package/module.py'>
>>> import sys
>>> sys.modules['package']
<module 'package' from '/home/vaultah/package/__init__.py'>
>>> sys.modules['package.module']
<module 'package.module' from '/home/vaultah/package/module.py'>

나는 당신에게 경고해야한다고 생각합니다. 특히 프로젝트가 복잡한 구조를 가지고 있다면 .


부수적으로, PEP 8 은 절대 수입의 사용을 권장하지만, 일부 시나리오에서는 명시 적 상대 수입이 허용된다고 명시합니다.

절대적으로 가져 오기는 일반적으로 더 읽기 쉽고 더 나은 동작을하는 경향이 있으므로 (또는 적어도 더 나은 오류 메시지를 표시 함) 권장됩니다. [...] 그러나 명시 적 상대 가져 오기는 절대 가져 오기를 대신 할 수있는 대안입니다. 특히 절대 가져 오기를 사용하는 것이 불필요하게 자세한 복잡한 패키지 레이아웃을 처리 할 때 특히 그렇습니다.


3
__package__이름이 __main__문제를 해결하기 위해 수동으로 설정할 수 있습니까?
Paulo Scardine

고마워, 좋은 답변! 모듈을 사용하여 imp모듈 을로드하고 __package__그에 따라 설정할 수 있었지만 결과는 분명히 안티 패턴입니다.
Paulo Scardine

오류가 발생 AttributeError: 'PosixPath' object has no attribute 'path'합니다.
사용자

빠른 답변 감사합니다. nltk 패키지를 사용하고 있는데, 오류가 발생했습니다 :`nltk.decorators의 <module>에있는 파일 "/usr/local/lib/python3.5/dist-packages/nltk/__init__.py", 115 행 데코레이터 가져 오기, <module>의 파일 "/usr/local/lib/python3.5/dist-packages/nltk/decorators.py", 23 행, sys.path = [ "nltk 인 경우 sys.path의 p p "not in p] <listcomp>의 23 행,"/usr/local/lib/python3.5/dist-packages/nltk/decorators.py "파일 sys.path = [p.sys 인 경우 p의 p nltk "not in p] TypeError : 'PosixPath'유형의 인수를 반복 할 수 없습니다`
사용자

1
파일 경로로 파일을 가져올 수도 있습니다 (상대도) : docs.python.org/3/library/…
Ctrl-C

84

이것을 패키지의 __init__.py 파일 안에 넣으십시오 .

# For relative imports to work in Python 3.6
import os, sys; sys.path.append(os.path.dirname(os.path.realpath(__file__)))

패키지가 다음과 같다고 가정합니다.

├── project
   ├── package
      ├── __init__.py
      ├── module1.py
      └── module2.py
   └── setup.py

이제 다음과 같이 패키지에서 정기적으로 가져 오기를 사용하십시오.

# in module2.py
from module1 import class1

이것은 파이썬 2와 3 모두에서 작동합니다.


우리는 WEEL로이 작품 패키지 않는 경우
알렉스 Punnen에게

1
또한 이것은 더 많은 표를받을 가치가 있다고 생각합니다. 이것을 __init__.py모두 넣으면 기본적으로 모든 상대적인 가져 오기 오류가 해결됩니다.
frankliuao

3
다른 사람과 대화 할 수는 없지만 sys.path다른 코드에 영향을 줄 수 있기 때문에 수정하지 않는 경향이 있습니다. (나는 그것이 작동하는 방법의 복잡성을 모르기 때문에 일부입니다.)
pianoJames

@pianoJames 나는 당신이 의미하는 바를 알고 있습니다. 그러나 작동합니다. 이것이 부작용이 있는지 알고있는 사람들은 알지 못할 것입니다.
Jon

나는 이것을 지금 사용하고 있습니다.
javadba

37

나는이 문제에 부딪쳤다. 해킹 해결 방법은 다음과 같은 if / else 블록을 통해 가져옵니다.

#!/usr/bin/env python3
#myothermodule

if __name__ == '__main__':
    from mymodule import as_int
else:
    from .mymodule import as_int


# Exported function
def add(a, b):
    return as_int(a) + as_int(b)

# Test function for module  
def _test():
    assert add('1', '1') == 2

if __name__ == '__main__':
    _test()

29
그것은 좋은 해결책이 아닙니다. 또한, except:나쁘다. 사용하는 except ImportError:대신!
ThiefMaster

6
그것은이다 SystemError여기. (Py 3.4)
Avi

8
이것은 끔찍한 아이디어는 아니지만 시도 / 제외보다는 사용할 가져 오기를 감지하는 것이 좋습니다. 같은 것 if __name__ == '__main__': from mymod import as_int; else: from .mymod import as_int.
퍼킨스

@Perkins 음 ... 대부분의 경우 그렇지 않습니다 . 그래도 상대 수입품은 예외라고 생각합니다.
wizzwizz4 2016 년

8

바라건대, 이것은 누군가에게 가치가있을 것입니다-나는 위에 게시 된 것과 비슷한 상대적 수입을 알아 내려고하는 6 개의 스택 오버 플로우 게시물을 겪었습니다. 나는 제안대로 모든 것을 설정했지만 여전히 타격을 받고 있었다ModuleNotFoundError: No module named 'my_module_name'

로컬에서 개발하고 놀았 기 때문에 setup.py파일을 만들거나 실행하지 않았습니다 . 또한 분명히 내 설정하지 않았습니다 PYTHONPATH.

테스트가 모듈과 동일한 디렉토리에있을 때와 같이 코드를 실행했을 때 모듈을 찾을 수 없다는 것을 깨달았습니다.

$ python3 test/my_module/module_test.py                                                                                                               2.4.0
Traceback (most recent call last):
  File "test/my_module/module_test.py", line 6, in <module>
    from my_module.module import *
ModuleNotFoundError: No module named 'my_module'

그러나 경로를 명시 적으로 지정하면 작업이 시작되었습니다.

$ PYTHONPATH=. python3 test/my_module/module_test.py                                                                                                  2.4.0
...........
----------------------------------------------------------------------
Ran 11 tests in 0.001s

OK

따라서 누군가가 몇 가지 제안을 시도한 경우 코드가 올바르게 구성되어 있다고 생각하고 현재 디렉토리를 PYTHONPATH로 내 보내지 않으면 다음 중 하나를 시도해보십시오.

  1. 코드를 실행하고 다음과 같이 경로를 명시 적으로 포함하십시오. $ PYTHONPATH=. python3 test/my_module/module_test.py
  2. 을 호출하지 않으 PYTHONPATH=.려면 setup.py다음과 같은 내용 으로 파일을 작성하고 python setup.py development패키지를 경로에 추가하십시오.
# setup.py
from setuptools import setup, find_packages

setup(
    name='sample',
    packages=find_packages()
)

6

메인 프로젝트 디렉토리에서 python3을 실행해야 작동했습니다.

예를 들어 프로젝트의 구조가 다음과 같은 경우

project_demo/
├── main.py
├── some_package/
   ├── __init__.py
   └── project_configs.py
└── test/
    └── test_project_configs.py

해결책

project_demo / 폴더 내에서 python3을 실행 한 다음

from some_package import project_configs

4

이 문제를 피하기 위해 패키지 패키지 로 솔루션을 고안 했습니다. lib 경로에 상위 디렉토리를 추가합니다.

import repackage
repackage.up()
from mypackage.mymodule import myfunction

리 패키지는 지능형 전략 (콜 스택 검사)을 사용하여 광범위한 사례에서 작동하는 상대적 가져 오기를 수행 할 수 있습니다.


지금까지 가장 쉬운 해결책! 감사합니다!
CodingInCircles

1
감사! 최상의 답변을 제공하는 대신 유용한 답변을하려고했습니다. :-)
fralau

3

두 패키지가 모두 가져 오기 경로 (sys.path)에 있고 원하는 모듈 / 클래스가 example / example.py 인 경우 상대 가져 오기없이 클래스에 액세스하려면 다음을 시도하십시오.

from example.example import fkt

1

가장 좋은 해결책은 모듈에 대한 패키지를 만드는 것입니다. 여기 에 방법에 대한 자세한 정보가 있습니다.

패키지가 있으면 상대 수입에 대해 걱정할 필요가 없으며 절대 수입 만 할 수 있습니다.


0

비슷한 문제가 발생했습니다. 공통 상수를 사용하여 협력하는 Linux 서비스 및 cgi 플러그인이 필요했습니다. 이것을하는 '자연적인'방법은 그것들을 init에 두는 것입니다 은 패키지 .py에 하지만 -m 매개 변수로 cgi 플러그인을 시작할 수 없습니다.

내 최종 솔루션은 위의 솔루션 # 2와 유사했습니다.

import sys
import pathlib as p
import importlib

pp = p.Path(sys.argv[0])
pack = pp.resolve().parent

pkg = importlib.import_module('__init__', package=str(pack))

단점은 상수 (또는 공통 함수) 앞에 pkg를 붙여야한다는 것입니다.

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