115

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

ディレクトリレイアウト

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

init.pyの内容

package/__init__.pyとは両方ともpackage/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はこれを望んでいません:「moduleという名前のモジュールがありません」というメッセージで失敗します。しかし…</p>

# 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.
4

3 に答える 3

95

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という名前のモジュールから...」という意味です。モジュールにつながるパッケージをインポートすることによって、モジュールのパスを「段階的に」構築する方法はありません。インポートするときは、常にモジュール名全体を参照する必要があります。

何を達成しようとしているのかは明確ではありません。特定のオブジェクト属性1のみをインポートする場合は、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

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

from package.subpackage import module
attribute1 = module.attribute1
attribute1 # works
module.someOtherAttribute #also works
于 2012-09-01T17:09:37.363 に答える
11

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

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

また:

from package.subpackage import module
print module.attribute1
于 2012-09-01T16:50:33.937 に答える
0

グローバル名前空間でattribute1を取得するだけの場合は、バージョン3で問題ないようです。なぜそれは過剰なプレフィックスですか?

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

from module import attribute1

できるよ

attribute1 = module.attribute1
于 2012-09-01T16:54:27.033 に答える