Python : 하위 패키지 또는 하위 모듈 가져 오기


90

이미 플랫 패키지를 사용하고 있었기 때문에 중첩 된 패키지에서 발생한 문제를 예상하지 못했습니다. 여기 ...

디렉토리 레이아웃

dir
 |
 +-- test.py
 |
 +-- package
      |
      +-- __init__.py
      |
      +-- subpackage
           |
           +-- __init__.py
           |
           +-- module.py

init .py의 내용

모두 package/__init__.pypackage/subpackage/__init__.py비어 있습니다.

의 내용 module.py

# file `package/subpackage/module.py`
attribute1 = "value 1"
attribute2 = "value 2"
attribute3 = "value 3"
# and as many more as you want...

내용 test.py(3 개 버전)

버전 1

# file test.py
from package.subpackage.module import *
print attribute1 # OK

그것은 사물을 가져 오는 (일괄 가져 오기)의 나쁘고 안전하지 않은 방법이지만 작동합니다.

버전 2

# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
from module import attribute1

더 안전한 방법으로 항목별로 가져 오지만 실패합니다. Python은 이것을 원하지 않습니다. "No module named module"메시지와 함께 실패합니다. 그러나…

# file test.py
import package.subpackage.module
from package.subpackage import module # Alternative
print module # Surprise here

… 말한다 <module 'package.subpackage.module' from '...'>. 그래서 그것은 모듈이지만 그것은 모듈이 아닙니다 / -P 8-O ... 어

버전 3

# file test.py v3
from package.subpackage.module import attribute1
print attribute1 # OK

이것은 작동합니다. 그래서 당신은 항상 overkill 접두사를 사용하거나 버전 # 1에서와 같이 안전하지 않은 방법을 사용하고 Python에서 안전하고 편리한 방법을 사용하는 것을 허용하지 않습니까? 안전하고 불필요한 긴 접두사를 피하는 더 좋은 방법은 Python이 거부하는 유일한 방법입니까? 그것을 사랑하기 때문이다 import *하거나 (이 연습을 시행하는 데 도움이되지 않습니다) 너무 긴 접두사를 사랑하기 때문에?

어려운 말로 미안하지만이 멍청한 행동을 해결하려고 노력하는 이틀입니다. 내가 어딘가에서 완전히 틀린 것이 아니라면, 파이썬의 패키지 및 하위 패키지 모델에서 무언가가 정말로 망가 졌다는 느낌이들 것입니다.

메모

  • 나는 sys.path글로벌 부작용을 피하기 위해, 또는 동일한 글로벌 효과 *.pth를 가지고 놀 수있는 또 다른 방법 인 파일 에 의존하고 싶지 않습니다 sys.path. 솔루션이 깨끗하려면 로컬에만 있어야합니다. Python은 하위 패키지를 처리 ​​할 수 ​​있지만 그렇지 않은 경우에도 로컬 작업을 처리 할 수 ​​있도록 전역 구성을 사용할 필요가 없습니다.
  • 나는 또한에서 가져 오기를 사용해 보았지만 package/subpackage/__init__.py아무것도 해결하지 subpackage못했고 똑같이 수행 하며 알려진 모듈이 아니라고 불평 print subpackage하고 모듈이라고 말합니다 (이상한 동작).

내가 완전히 틀렸을 수도 있지만 (내가 선호하는 옵션) 파이썬에 대해 많이 실망하게 만듭니다.

내가 시도한 세 가지 외에 다른 알려진 방법이 있습니까? 내가 모르는 것?

(한숨)

----- % <----- 편집 -----> % -----

지금까지의 결론 (사람들의 의견 후)

모든 패키지 참조가 전역 사전으로 이동하기 때문에 Python의 실제 하위 패키지와 같은 것은 없습니다. 즉, 로컬 패키지 참조를 관리 할 방법이 없음을 의미하는 로컬 사전이 없음을 의미합니다.

전체 접두사 또는 짧은 접두사 또는 별칭을 사용해야합니다. 에서와 같이 :

전체 접두사 버전

from package.subpackage.module import attribute1
# An repeat it again an again
# But after that, you can simply:
use_of (attribute1)

짧은 접두사 버전 (하지만 반복되는 접두사)

from package.subpackage import module
# Short but then you have to do:
use_of (module.attribute1)
# and repeat the prefix at every use place

또는 위의 변형입니다.

from package.subpackage import module as m
use_of (m.attribute1)
# `m` is a shorter prefix, but you could as well
# define a more meaningful name after the context

분해 된 버전

한 번에 여러 항목을 일괄 적으로 가져 오는 것이 마음에 들지 않으면 다음을 수행 할 수 있습니다.

from package.subpackage.module import attribute1, attribute2
# and etc.

내가 가장 좋아하는 취향은 아니지만 (수입 법인 당 하나의 수입 명세서를 선호 함) 개인적으로 선호하는 것이 될 수 있습니다.

업데이트 (2012-09-14) :

마침내 레이아웃에 대한 주석을 제외하고는 실제로 괜찮은 것처럼 보입니다. 위의 대신 다음을 사용했습니다.

from package.subpackage.module import (

    attribute1, 
    attribute2,
    attribute3,
    ...)  # and etc.

"from. import module"을 "/package/subpackage/__init__.py"에 쓰면 어떻게 되나요?
Markus Unterwaditzer

당신의 "인수 화 된 버전"은 당신이하고 싶은 일에 정확히 맞는 것 같습니다. attribute1 및 attribute2에 대해 별도의 가져 오기 행을 수행하는 경우 ( "선호하는"대로), 의도적으로 더 많은 작업을 수행하는 것입니다. 그렇게 할 이유가 없습니다.
BrenBarn

죄송합니다. 원하는 것을 얻지 못했습니다. 질문을 더 명확하게 바꿔 줄 수 있습니까? 정확히 무엇을 하시겠습니까? 내 말은, 작동하지 않는 내용을 작성하고 어떻게 작동하길 기대하십니까? 내가 읽은 내용으로 나는 수입의 의미가 Java 또는 C와 같은 의미를 포함한다고 생각합니다. 마지막으로 별을 가져올 __all__때 내 보내야하는 이름 목록을 포함 하는 변수를 추가하여 안전하게 모듈 "별 가져 오기"를 만들 수 있습니다 . 편집 : 좋아, BrenBarn 답변을 읽고 당신이 의미하는 바를 이해했습니다.
Bakuriu

답변:


68

import모듈을 검색 하는 방법을 오해하는 것 같습니다 . import 문을 사용하면 항상 실제 모듈 경로 (및 / 또는 sys.modules)를 검색합니다 . 이전 가져 오기로 인해 존재하는 로컬 네임 스페이스 의 모듈 객체 를 사용하지 않습니다 . 당신이 할 때 :

import package.subpackage.module
from package.subpackage import module
from module import attribute1

두 번째 줄은라는 패키지를 찾고 해당 패키지에서 package.subpackage가져옵니다 module. 이 줄은 세 번째 줄에 영향을주지 않습니다. 세 번째 줄은 호출 된 모듈을 module찾지 만 찾지 못합니다. module위의 줄에서 가져온 호출 된 개체를 "재사용"하지 않습니다 .

즉, from someModule import ..."이전에 가져온 someModule이라는 모듈에서 ..."라는 의미가 아니라 "sys.path에서 찾은 someModule이라는 모듈에서 ..."를 의미합니다. 모듈로 연결되는 패키지를 가져 와서 모듈의 경로를 "점진적으로"빌드하는 방법은 없습니다. 가져올 때 항상 전체 모듈 이름을 참조해야합니다.

달성하려는 목표가 명확하지 않습니다. 특정 개체 attribute1 만 가져 오려면 수행 from package.subpackage.module import attribute1하고 수행하면됩니다. package.subpackage.module원하는 이름을 가져온 후에는 오랫동안 걱정할 필요가 없습니다 .

당신이 경우 않는 다른 이름 나중에 액세스 모듈에 액세스 할 수 있도록하려면, 당신은 할 수 from package.subpackage import module당신이 다음 할 수있는 보았 듯이, 그리고 module.attribute1당신 같은 등등 많은.

당신이 원하는 경우 모두를 원하는 경우 --- 즉, attribute1직접 액세스 하고 당신이 원하는 module접근, 바로 위의 두 가지를 모두 수행 :

from package.subpackage import module
from package.subpackage.module import attribute1
attribute1 # works
module.someOtherAttribute # also works

package.subpackage두 번 입력하는 것을 좋아하지 않는 경우 attribute1에 대한 로컬 참조를 수동으로 만들 수 있습니다.

from package.subpackage import module
attribute1 = module.attribute1
attribute1 # works
module.someOtherAttribute #also works

귀하의 의견은 Ignacio Vazquez-Abrams의 의견과 동일한 방향으로 진행됩니다 (그의 메시지에 의견을 남겼습니다). 마지막에 추가하는 module.attribute1것은 사용 에 관한 것이지만 모든 곳에서 접두사의 필요성을 피할 수있는 방법이 있지만. 따라서 모든 위치에 접두사를 사용하거나 로컬 별칭을 만들어 이름을 반복해야합니다. 내가 기대했던 스타일은 아니지만 방법이 없다면 (결국 이름 변경 선언과 비슷한 것을 요구하는 Ada에 익숙합니다).
Hibou57

@ Hibou57 : "버전 2"에서 수행하려는 작업이 아직 명확하지 않습니다. 불가능한 일을 하시겠습니까? 패키지 / 모듈 / 속성 이름의 어떤 부분도 다시 입력하지 않고 모듈과 속성을 모두 가져오고 싶습니까?
BrenBarn

로컬 개체 참조를 가질 수있는 방법과 마찬가지로 로컬 패키지 참조를 갖고 싶었습니다. 마침내 실제로 로컬 모듈 참조가있는 것 같지만 이들에서 가져올 수 없습니다. 재미있는 취향을 가진 지역과 글로벌의 혼합입니다 (일부는 지역적 일 수 있고 다른 것들은 전역 적이어야합니다. 나는 그것을 좋아하지 않지만, 이제 그것이 어떻게 작동하는지 더 잘 이해하는 한 괜찮습니다). 그건 그렇고 당신의 메시지에 감사드립니다.
Hibou57

1
어떻게 작동하는지 아직 이해하지 못합니다. 아니면 2012 년에 그랬습니다.
Hejazzman

1
6 개월의 정리 해고 후에 파이썬으로 돌아올 때마다 여기에 도착합니다. 이 페이지를 방문 할 때마다 찬성 할 수만 있다면! 저는이 문장으로 거대한 포스터를 만들 것입니다. "모듈로 이어지는 패키지를 가져 와서 모듈의 경로를"점진적으로 "구축 할 방법은 없습니다."
PatrickT

10

# 2가 실패하는 이유 sys.modules['module']는 존재하지 않고 (가져 오기 루틴에 자체 범위가 있고 module로컬 이름을 볼 수 없음 ) module디스크에 모듈이나 패키지 가 없기 때문 입니다. 가져온 여러 이름을 쉼표로 구분할 수 있습니다.

from package.subpackage.module import attribute1, attribute2, attribute3

또한:

from package.subpackage import module
print module.attribute1

sys.modules['name']내가 지금까지 몰랐던 당신의 언급은 그것이 내가 두려워하는 것이라고 생각하게 만들었습니다 (그리고 BrenBarn은 확인합니다). 파이썬에서 실제 하위 패키지와 같은 것은 없습니다. sys.modules이름에서 알 수 있듯이 전역 적이며 모듈에 대한 모든 참조가 이것에 의존한다면 모듈에 대한 로컬 참조와 같은 것은 없습니다 (Python 3.x와 함께 제공 될 수 있습니까?).
Hibou57

"참조"의 사용이 모호합니다. import# 2 의 첫 번째 는에 package.subpackage.module바인딩 할 로컬 참조를 생성합니다 module.
Ignacio Vazquez-Abrams

네,하지만 ;-) 내가 가져올 수없는 "모듈"의
Hibou57

0

전역 네임 스페이스에서 attribute1을 가져 오는 것뿐이라면 버전 3은 괜찮아 보입니다. 왜 과도한 접두사입니까?

버전 2에서는

from module import attribute1

넌 할 수있어

attribute1 = module.attribute1

attribute1 = module.attribute1부가 가치없이 이름을 반복하는 것입니다. 나는 그것이 효과가 있다는 것을 알고 있지만, 나는이 스타일이 마음에 들지 않는다 (당신의 대답이 마음에 들지 않는다는 것을 의미하지는 않는다).
Hibou57

2
나는 여기에 언급하는 모든 사람들과 마찬가지로 당신이 무엇을 원하는지 이해하지 못하는 것 같습니다. 제공하는 모든 예제에서 네임 스페이스에있는 하위 패키지의 기호로 끝나고 싶은 것처럼 보입니다. 작동하지 않는 예제 (예 2)는 패키지에서 하위 모듈을 가져온 다음 해당 하위 모듈에서 기호를 가져 와서 수행하려고합니다. 왜 한 단계가 아닌 두 단계로 하려는지 모르겠습니다. 이상적인 솔루션이 무엇이고 왜 그런지 더 설명 할 수 있습니다.
토마스 밴더 Stichele
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.