web-dev-qa-db-ja.com

Python:プロジェクト階層の同じレベルにある別のディレクトリからモジュールをインポートします

あらゆる種類の例やその他の同様の質問を見てきましたが、私のシナリオに完全に一致する例を見つけることができないようです。似たような質問が非常に多いので、これを尋ねるのは本当に愚かなことのように感じますが、これを「正しく」動作させることができないようです。これが私のプロジェクトです。

user_management  (package)
        |
        |------- __init__.py
        |
        |------- Modules/
        |           |
        |           |----- __init__.py
        |           |----- LDAPManager.py
        |           |----- PasswordManager.py
        |
        |------- Scripts/
        |           |
        |           |----- __init__.py
        |           |----- CreateUser.py
        |           |----- FindUser.py

「CreateUser.py」をメインのuser_managementディレクトリに移動すると、"import Modules.LDAPManager"を使用してLDAPManager.pyをインポートできます---これは機能します。私ができないこと(私がしたいこと)は、CreateUser.pyをScriptsサブフォルダーに保持し、LDAPManager.pyをインポートすることです。私は"import user_management.Modules.LDAPManager.py"を使用してこれを達成したいと思っていました。これは機能しません。つまり、Pythonファイルを取得して階層をより深く見ることができますが、Pythonスクリプトを使用して1つのディレクトリを上下に参照することはできません。

以下を使用して問題を解決できることに注意してください。

sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
import Modules.LDAPManager as LDAPManager

これは悪い習慣であり、落胆すると聞いています。

スクリプトのファイルは直接実行されることを意図しています(スクリプトのinit。pyは必要ですか?)。この場合、-mフラグを指定してCreateUser.pyを実行する必要があることを読みました。これについていくつかのバリエーションを試しましたが、CreateUser.pyにLDAPManager.pyを認識させることができないようです。

68
CptSupermrkt

CreateUser.pyをメインのuser_managementディレクトリに移動すると、import Modules.LDAPManagerをインポートしてLDAPManager.pyを簡単に使用できます。これは機能します。

しないでください。このようにして、LDAPManagerによって使用されるCreateUserモジュールは、notは他のインポートを介してインポートされたモジュールと同じになります。これは、モジュール内にグローバルな状態がある場合、またはpickle/unpickling中に問題を引き起こす可能性があります。 Avoidインポートは、モジュールが同じディレクトリにあるためにのみ機能します。

パッケージ構造がある場合、次のいずれかを行う必要があります。

  • 相対インポートを使用します。つまり、CreateUser.pyScripts/にある場合:

     from ..Modules import LDAPManager
    

    これはwaspast時制に注意してください) PEP 8 = pythonの古いバージョンはそれらをあまりよくサポートしていなかったからですが、この問題は数年前に解決されました。 currentバージョンのPEP 8doesは、それらを絶対インポートの代替として受け入れられることを示唆しています。私は実際にパッケージ内でlikeしています。

  • パッケージ名全体を使用して絶対インポートを使用しますCreateUser.py in Scripts/):

     from user_management.Modules import LDAPManager
    

2番目のパッケージが機能するには、user_managementPYTHONPATH内にインストールする必要があります。開発中にIDEを設定して、手動でsys.path.appendへの呼び出しを追加することなく、これを実現できます。

また、Scripts/がサブパッケージであることは奇妙に感じます。実際のインストールでは、user_managementモジュールはsite-packagesディレクトリ(OSにライブラリをインストールするために使用されるディレクトリ)にあるlib/の下にインストールされるため、スクリプトをインストールする必要があるためbin/ディレクトリの下(OSの実行可能ファイルが含まれている方)。

実際、Script/user_managementの下にあるべきではないと考えています。 user_managementと同じレベルである必要があります。この方法では、not-mを使用する必要がありますが、単にパッケージが見つかることを確認する必要があります(これもIDEの構成の問題です。パッケージを正しくインストールするか、PYTHONPATH=. python Scripts/CreateUser.pyを使用して正しいパスでスクリプトを起動します)。


要約すると、使用する階層Iは次のとおりです。

user_management  (package)
        |
        |------- __init__.py
        |
        |------- Modules/
        |           |
        |           |----- __init__.py
        |           |----- LDAPManager.py
        |           |----- PasswordManager.py
        |

 Scripts/  (*not* a package)
        |  
        |----- CreateUser.py
        |----- FindUser.py

次に、CreateUser.pyFindUser.pyのコードは、絶対インポートを使用してモジュールをインポートする必要があります。

from user_management.Modules import LDAPManager

インストール中に、user_managementPYTHONPATHのどこかにあること、およびモジュールを見つけることができるように、実行可能ファイルのディレクトリ内のスクリプトを確認します。開発中は、IDE構成に依存するか、CreateUser.py親ディレクトリをPYTHONPATHに追加してScripts/を起動します(両方のuser_managementおよびScripts):

PYTHONPATH=/the/parent/directory python Scripts/CreateUser.py

または、PYTHONPATHをグローバルに変更して、毎回これを指定する必要がないようにすることができます。 UNIX OS(Linux、Mac OS Xなど)では、シェルスクリプトの1つを変更してPYTHONPATH外部変数を定義できます。Windowsでは、環境変数の設定を変更する必要があります。


補遺python2を使用している場合は、次のように入力して、暗黙の相対インポートを回避することを確認した方がよいと考えています。

from __future__ import absolute_import

モジュールの上部。このようにimport XalwaystoplevelモジュールXをインポートすることを意味し、インポートを試みません同じディレクトリにあるX.pyファイル(そのディレクトリがPYTHONPATHにない場合)。このように、相対インポートを行うonly方法は、explicit構文(from . import X)を使用することです。これは優れています(explicitはimplicitよりも優れています)。

これにより、「間違った」暗黙的な相対インポートを使用しないようにすることができます。これは、何かが間違っていることを明確に示すImportErrorを生成するためです。それ以外の場合は、自分が思っているものとは異なるモジュールを使用できます。

59
Bakuriu

Python 2.5以降では、次を使用できます。

from ..Modules import LDAPManager

先行期間では、階層のレベルを「上げる」ことができます。

インポートについては、 パッケージ内参照 のPythonドキュメントを参照してください。

14
jonrsharpe

「ルート」__init__.pyでは、次のこともできます。

import sys
sys.path.insert(1, '.')

これにより、両方のモジュールがインポート可能になります。

2
rdodev