web-dev-qa-db-ja.com

パッケージ内のPython)のトップレベルモジュールを参照するにはどうすればよいですか?

以下の階層では、以下のすべての.pyファイルで一般的な用語を使用してtop_packageを参照するための便利で普遍的な方法はありますか? 「top_package」の名前が変更されても何も壊れないように、他のモジュールをインポートするための一貫した方法が必要です。

相対パスは以下の各pythonファイル。

  1. 各pythonファイルは、パッケージ内の同じモジュールに対して同じインポートステートメントを持つことができます。
  2. パッケージ内の.pyファイル内の「top_package」へのデカップリング参照。したがって、「top_package」という名前がどのように変更されても、何も壊れません。

    top_package/
      __init__.py
      level_one_a/
        __init__.py
        my_lib.py
        level_two/
          __init__.py
          hello_world.py
      level_one_b/
        __init__.py
        my_lib.py
      main.py
    
20
hllau

これでうまくいくはずです:

top_package = __import__(__name__.split('.')[0])

ここでの秘訣は、すべてのモジュールについて、__name__変数に、たとえばtop_package.level_one_a.my_libなどのドットで区切られたモジュールへのフルパスが含まれていることです。したがって、最上位のパッケージ名を取得する場合は、パスの最初のコンポーネントを取得し、__import__を使用してインポートする必要があります。

パッケージへのアクセスに使用される変数名はまだtop_packageと呼ばれていますが、パッケージの名前を変更でき、それでも機能するかどうかを確認できます。

13
jcollado

パッケージとmainスクリプトを次のように外部コンテナディレクトリに配置します。

container/
    main.py
    top_package/
        __init__.py
        level_one_a/
            __init__.py
            my_lib.py
            level_two/
                __init__.py
                hello_world.py
        level_one_b/
            __init__.py
            my_lib.py

main.pyが実行されると、その親ディレクトリ(container)がsys.pathの先頭に自動的に追加されます。また、top_packageは同じディレクトリにあるため、パッケージツリー内のどこからでもインポートできます。

したがって、hello_world.pyは次のようにlevel_one_b/my_lib.pyをインポートできます。

from top_package.level_one_b import my_lib

コンテナディレクトリの名前や場所に関係なく、インポートは常にこの配置で機能します。

ただし、元の例では、top_packageはコンテナディレクトリ自体として簡単に機能する可能性があることに注意してください。 top_package/__init__.pyを削除するだけで、効果的に同じ配置が残ります。

前のインポートステートメントは次のように変更されます。

from level_one_b import my_lib

top_packageの名前は自由に変更できます。

7
ekhumoro

パッケージの __import__() 関数と __path__ 属性の組み合わせを使用できます。

たとえば、パッケージ内の別の場所から<whatever>.level_one_a.level_two.hello_worldをインポートするとします。あなたはこのようなことをすることができます:

import os
_temp = __import__(__path__[0].split(os.sep)[0] + ".level_one_a.level_two.hello_world")
my_hello_world = _temp.level_one_a.level_two.hello_world

このコードはトップレベルパッケージの名前に依存せず、パッケージ内のどこでも使用できます。それもかなり醜いです。

1
srgerg

これは、ライブラリモジュール内から機能します。

import __main__ as main_package
TOP_PACKAGE = main_package.__package__.split('.')[0]
0
Apalala

相対的なインポートまたは名前付きパッケージを使用しないと、#2は不可能だと思います。名前を明示的に呼び出すか、相対インポートを使用して、インポートするモジュールを指定する必要があります。そうでなければ、通訳はあなたが何を望んでいるのかをどうやって知るのでしょうか?

アプリケーションランチャーをtop_level/の1レベル上に作成し、それをimport top_levelにすると、top_levelパッケージ内のどこからでもtop_level.*を参照できます。

(私が取り組んでいるソフトウェアの例をお見せできます: http://github.com/toddself/beerlog/

0
tkone