1. ホーム
  2. python

[解決済み] Python: サブパッケージやサブモジュールのインポート

2022-09-07 11:14:54

質問

フラットパッケージをすでに使っていたので、ネストされたパッケージで遭遇した問題は予想外でした。これは...

ディレクトリのレイアウト

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はこれを望んでいません: "モジュールという名前のモジュールがありません"というメッセージで失敗します。しかし ...

# 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

こちらは動作します。つまり、常に過剰なプレフィックスを使わざるを得ないか、バージョン#1のような安全でない方法を使い、安全で便利な方法を使うことはPythonに拒否されるということですか?安全で不必要な長いプレフィックスを避けるより良い方法は、Pythonが拒否する唯一の方法なのでしょうか?これは import * が好きだからなのか、それとも長い接頭辞が好きだからなのか(これはこの慣習を強制するのに役立ちません)?

難しい言葉で申し訳ありませんが、この愚かなような動作を回避するために2日間試行錯誤しています。私がどこかで完全に間違っていない限り、これは、Python のパッケージとサブパッケージのモデルで何かが本当に壊れているような気がしています。

ノート

  • に頼りたくない。 sys.path には頼りたくないし、グローバルな副作用を避けるために *.pth ファイルでもありません。 sys.path を同じグローバルな効果で再生する別の方法です。解決策がクリーンであるためには、それはローカルでなければなりません。Pythonはサブパッケージを扱うことができ、そうでないこともありますが、ローカルなものを扱えるようにするためにグローバルな設定を弄る必要はないはずです。
  • でimportを使うことも試してみました。 package/subpackage/__init__.py でも、それは何も解決しません、それは同じことをして、文句を言う subpackage は既知のモジュールではないのに print subpackage はそれがモジュールであると言っています (奇妙な動作です、もう一度)。

私が完全に間違っているのかもしれませんが(私が望む選択肢)、これはPythonについて多くの失望を感じさせてくれます。

私が試した3つの方法の他に既知の方法はありますか?私が知らない何か?

(ため息)

----- %< ----- 編集 ----- >% -----

ここまでの結論(みんなのコメントを受けて)

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.

私の最初の好みのテイストではありませんが(私はインポートされたエンティティごとに1つのインポート文を持つことを好みます)、私が個人的に好むであろうものであるかもしれません。

更新 (2012-09-14)。

最後にレイアウトについてのコメントを除いて、実際には問題ないようです。上記の代わりに、私は使用しました。

from package.subpackage.module import (

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

どのように解決するのですか?

あなたは、以下の方法を誤解しているようです。 import がモジュールを検索する方法を誤解しているようです。 import ステートメントを使用すると 常に は実際のモジュールのパスを検索します (そして sys.modules を使用しません。 オブジェクト を利用しません。 そうすると

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

2行目は package.subpackage というパッケージを探し、インポートします。 module をそのパッケージから削除します。 この行は3行目には何の影響も及ぼしません。 3 行目は、単に 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