web-dev-qa-db-ja.com

Python:サブパッケージまたはサブモジュールのインポート

既にフラットパッケージを使用しているので、ネストされたパッケージで発生する問題を予期していませんでした。ここは…

ディレクトリレイアウト

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 ... uh

バージョン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はサブパッケージを処理できますが、そうでない場合もありますが、ローカルなものを処理できるようにするためにグローバル構成を操作する必要はありません。
  • 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.
67
Hibou57

importがモジュールを検索する方法を誤解しているようです。 importステートメントを使用すると、alwaysは実際のモジュールパス(および/またはsys.modules)を検索します。以前のインポートのために存在するローカル名前空間のモジュールobjectsを使用しません。行うとき:

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について心配する必要はありません。

do後で他の名前にアクセスするためにモジュールにアクセスしたい場合は、from package.subpackage import moduleを実行できます。これまで見てきたように、module.attribute1などを実行できます好きなだけ。

both ---が必要な場合、つまりattribute1に直接アクセス可能にする場合andmoduleにアクセス可能にする場合は、上記の両方を実行します:

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

package.subpackageを2回入力するのが嫌な場合は、attribute1へのローカル参照を手動で作成できます。

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

#2が失敗する理由は、sys.modules['module']が存在せず(インポートルーチンに独自のスコープがあり、moduleローカル名を表示できないため)、moduleモジュールまたはパッケージが存在しないためです。ディスク。インポートされた複数の名前をコンマで区切ることができることに注意してください。

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

また:

from package.subpackage import module
print module.attribute1

グローバルネームスペースでattribute1を取得することだけが目的であれば、バージョン3は問題ありません。なぜそれはプレフィックスを過剰殺すのですか?

バージョン2では、代わりに

from module import attribute1

できるよ

attribute1 = module.attribute1