web-dev-qa-db-ja.com

Pythonのモジュールのインポートと__init__.py

Python(v2.7)のインポートメカニズムに関するベストプラクティスを理解しようとしています。私は少し成長し始めたプロジェクトがあり、私のコードは次のように構成されていると言えます:

foo/
    __init__.py
    Foo.py
    module1.py
    module2.py
    module3.py

パッケージ名はfooであり、その下にクラスFooのコードを含むモジュールFoo.pyがあります。したがって、パッケージ、モジュール、およびクラスに同じ名前を使用していますが、最初はあまり賢くないかもしれません。

__init__.pyは空であり、クラスFoomodule1, module2 and module3をインポートする必要があるため、Foo.pyファイルの一部は次のようになります。

# foo/Foo.py

import module1
import module2
import module3

class Foo(object):
    def __init__(self):
....
....
if __name__ == '__main__':
    foo_obj = Foo()

しかし、後でこれを再検討し、すべてのインポートを__init__.pyファイルに含める方が良いと考えました。したがって、私の__init__.pyは次のようになります。

# foo/__init__.py

import Foo
import module1
import module2
import module3
....
....

そして、私のFoo.pyfooのみをインポートする必要があります:

# foo/Foo.py

import foo

これは1つのライナーなので便利に見えますが、循環インポートを作成しているのではないかと少し心配しています。つまり、スクリプトFoo.pyが実行されると、可能な限りすべてがインポートされ、__init__.pyが呼び出され、Foo.pyが再度インポートされます(正しいですか?)。さらに、パッケージ、モジュール、およびクラスに同じ名前を使用すると、事態がさら​​に混乱します。

それは私がそれをやった方法で理にかなっていますか?または私はトラブルを求めていますか?

28
Aenaon

PEP 0008、「パブリックおよび内部インターフェース」

インポートされた名前は、常に実装の詳細と見なされる必要があります。他のモジュールは、os.pathやサブモジュールから機能を公開するパッケージの__init__モジュールなど、含まれるモジュールのAPIの明示的に文書化された部分でない限り、そのようなインポートされた名前への間接アクセスに依存してはなりません。

したがって、これは、__init__がサブモジュールから関数を公開するために使用されている場合、__init__モジュールにインポートを置くことはisであることを示唆します。 Here は、__init__のPythonの使用例をいくつか紹介した短いブログ投稿です。インポートを使用して、パッケージレベルでサブパッケージを使用可能にします。

Fooにインポートを1つだけにするためにインポートステートメントを__init__に移動する例は、notこのルールに従ってください。私の解釈では、__init__のインポートはexternalインターフェイスに使用する必要があります。そうでない場合は、インポートステートメントをそれらを必要とするファイルに入れるだけです。これにより、サブモジュール名が変更された場合のトラブルが軽減され、サブモジュールの異なるサブセットを使用するファイルを追加するときに、不要なインポートや見つけにくいインポートが発生しなくなります。

循環参照に関しては、これはPython( たとえば )で間違いなく可能です。実際にあなたのおもちゃの例を試す前にそれについて書きましたが、例を作るためにFoo.pyを1レベル上げる必要がありました。

Foo.py
foo/
    __init__.py
    module1.py
    module2.py
    module3.py

そのセットアップといくつかのprintステートメントで、python Foo.pyを実行すると出力が得られます:

module 1
module 2
module 3
hello Foo constructor

そして正常に終了します。これはif __name__ == "__main__"を追加することに起因することに注意してください-それ以外にprintステートメントを追加すると、Pythonはまだモジュールを2回ロードしています。より良い解決策は__init__.pyからインポートを削除します。前述したように、これらのサブモジュールが何であるかに応じて、それは意味をなさない場合があります。

4
user812786

ベストプラクティスについては、「Python Code」のスタイルガイド」を参照してください。インポートはそのガイドのクラスに保持されます。

https://www.python.org/dev/peps/pep-0008/#imports

1
Eagain

これを試して:

パッケージ1

package1.py

__init__.py

パッケージ2

test.py

package1.py:-

class abc:
    a = 'hello'
    def print_a(self):
    print(a)

init。py:-

from .package1 import abc

package2.py:-

From package1.package1 import abc

これらの__init__.pyを使用して、パッケージからインポートします。

1
Trishant Pahwa

これが正しい方法であるかどうかを明確に述べることはできませんが、常に前者の方法で行ってきました。つまり、私は常に__init__.pyを空にしておき、必要に応じてFoo.py内にインポートしました。

あなたがそれをどのように説明するかから、後者の形でいくつかの循環論理が起こっているように見えます。

0
brettb