上記のディレクトリにあるPythonクラスをインポートするにはどうすればよいですか?


212

現在のディレクトリより上のディレクトリにあるファイルのクラスを継承したい。

そのファイルを比較的インポートすることは可能ですか?

回答:


177

from ..subpkg2 import mod

Pythonのドキュメントごと:パッケージ階層内では、インポートステートメントのドキュメントにあるように、2つのドットを使用します。

インポートするモジュールを指定するときに、モジュールの絶対名を指定する必要はありません。モジュールまたはパッケージが別のパッケージに含まれている場合、パッケージ名を言及しなくても、同じトップパッケージ内で相対インポートを行うことができます。指定したモジュールまたはパッケージで先頭のドットを使用すると、from正確な名前を指定せずに現在のパッケージ階層を上に移動する高さを指定できます。先頭の1つのドットは、インポートを行うモジュールが存在する現在のパッケージを意味します。2つのドットは、1つのパッケージレベルを意味します。3つのドットは2レベル上にあります。したがってfrom . import modpkgパッケージ内のモジュールから実行すると、インポートされpkg.modます。from ..subpkg2 import mod内から実行するpkg.subpkg1と、インポートされますpkg.subpkg2.mod。相対インポートの仕様はPEP 328に含まれています。

PEP 328は、絶対/相対インポートを扱います。


4
up1 = os.path.abspath( '..')sys.path.insert(0、up1)
rp。

Pep 328では、Pythonバージョン:2.4、2、5、2.6のみが表示されます。バージョン3は、より知識のある魂に任されています。
ギメル

22
これによりエラーが発生しますValueError:トップレベルパッケージを超えて相対インポートを試みました
Carlo

4
ImportErrorの結果:既知の親パッケージなしで相対インポートを試みた
Rotkiv

116
import sys
sys.path.append("..") # Adds higher directory to python modules path.

1
これは私にとってはうまくいきます。これを追加した後、親モジュールを直接インポートできます。「..」を使用する必要はありません。
Evan Hu

8
これは、大まかに言えば、アプリケーションのPWD値(現在のディレクトリ)が親の子である場合にのみ機能します。したがって、たとえそれが機能したとしても、多くの種類の体系的な変更によってそれを取り除くことができます。
Phlip

これは私にとっても、より高いレベルのモジュールをインポートするためにも機能しました。これをos.chdir( "..")と一緒に使用して、より高いレベルの他のファイルをロードします。
Surendra Shrestha 2017

これは、上記のgimelの回答と同じエラーをトリガーするようです。
カルロ

81

@gimelの答えは、彼が言及するパッケージ階層を保証できる場合は正しいです。それができない場合(実際の必要性が表現どおりであり、ディレクトリのみに関連付けられており、パッケージ化に必要な関係がない場合)__file__、親ディレクトリを見つけるために作業する必要があります(いくつかのos.path.dirname呼び出しで実行できます。 - )、その後、(そのディレクトリが入っていない場合sys.pathプリペンド)一時的に非常にの開始時に言ったディレクトリを挿入sys.path__import__、削除が再びDIR言った-確かに汚い仕事を、しかし、(「ときあなたがしなければならない、あなたがしなければならない」とPyhonは、に取り組んでいますプログラマがやらなければならないことをやめないでください -ISO C標準が序文の「Spirit of C」セクションで述べているように!-)。

これはあなたのために働くかもしれない例です:

import sys
import os.path
sys.path.append(
    os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))

import module_in_parent_dir

2
これにより、Pythonパッケージ内のディレクトリが追加sys.pathされ、同じモジュールを異なる名前で使用できるようになり、対応するすべてのバグが発生する可能性があります。pypyのautopath.pyまたはツイストの_preamble.pyは、ディレクトリを上方向にたどりながら最上位パッケージを識別する検索条件を使用して解決します。
jfs 2014年

4
sys.path.remove(pathYouJustAdded)この新しいパスを保持しないようにするために、必要なインポート後に何かをしたい場合があります。
Matthias

35

現在のディレクトリの1つ上のレベルのディレクトリからモジュールをインポートします。

from .. import module

38
私は得ました:トップレベルのパッケージを超えて相対インポートを試みました:(
RicardoE

25
を使用し from .. import module てエラーが発生しましたValueError:推奨事項に従って非パッケージで相対インポートを
試行しました

4

ディレクトリであるモジュールをロードする方法

序文:私は以前の回答を大幅に書き直して、人々をpythonのエコシステムに容易に移行できるようにしたいと考えています。うまくいけば、pythonのインポートシステムを使用してすべての人に成功の最高の変化をもたらします。

これは、パッケージ内の相対的なインポートをカバーします。これは、OPの質問に対する最も可能性の高いケースだと思います。

Pythonはモジュラーシステムです

これが、次のように記述import fooするのではなく、ルート名前空間からモジュール「foo」をロードするように記述する理由です。

foo = dict();  # please avoid doing this
with open(os.path.join(os.path.dirname(__file__), '../foo.py') as foo_fh:  # please avoid doing this
    exec(compile(foo_fh.read(), 'foo.py', 'exec'), foo)  # please avoid doing this

Pythonはファイルシステムに結合されていません

これが、Jythonなどの仮想ファイルシステムを提供することなく、事実上のファイルシステムがない環境にPythonを埋め込むことができる理由です。

ファイルシステムから切り離されているため、インポートを柔軟に行うことができます。この設計により、アーカイブ/ zipファイルからのインポート、インポートシングルトン、バイトコードキャッシング、cffi拡張、さらにはリモートコード定義の読み込みなどが可能になります。

では、インポートがファイルシステムに結合されていない場合、「1つ上のディレクトリ」とはどういう意味ですか?いくつかのヒューリスティックを選択する必要がありますが、それは可能です。たとえば、パッケージ作業する場合、同じパッケージ内でのように相対的なインポート.foo..fooを行ういくつかのヒューリスティックがすでに定義されています。涼しい!

ソースコードの読み込みパターンをファイルシステムに結合したい場合は、それを行うことができます。独自のヒューリスティックを選択し、何らかのインポート機械を使用する必要があります。importlibをお勧めします

Pythonのimportlibの例は次のようになります。

import importlib.util
import sys

# For illustrative purposes.
file_path = os.path.join(os.path.dirname(__file__), '../foo.py')
module_name = 'foo'

foo_spec = importlib.util.spec_from_file_location(module_name, file_path)
# foo_spec is a ModuleSpec specifying a SourceFileLoader
foo_module = importlib.util.module_from_spec(foo_spec)
sys.modules[module_name] = foo_module
foo_spec.loader.exec_module(foo_module)

foo = sys.modules[module_name]
# foo is the sys.modules['foo'] singleton

パッケージング

ここで公式に利用できる素晴らしいサンプルプロジェクトがあります:https : //github.com/pypa/sampleproject

Pythonパッケージはソースコードに関する情報のコレクションであり、他のツールにソースコードを他のコンピューターにコピーする方法、およびソースコードをそのシステムのパスに統合して他のコンピューターで機能するようにする方法を通知できimport fooます(インタープリターに関係なく、ホストオペレーティングシステムなど)

ディレクトリ構造

fooいくつかのディレクトリ(できれば空のディレクトリ)にパッケージ名を入れましょう。

some_directory/
    foo.py  # `if __name__ == "__main__":`  lives here

私の好みはsetup.py、の兄弟として作成するfoo.pyことです。これにより、setup.pyファイルの書き込みが簡単になりますが、必要に応じて、デフォルトでsetuptoolsが行うすべてのことを変更/リダイレクトするように構成を書き込むことができます。たとえばfoo.py、「src /」ディレクトリの下に置くことはやや人気がありますが、ここでは扱いません。

some_directory/
    foo.py
    setup.py

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    py_modules=['foo'],
)

python3 -m pip install --editable ./  # or path/to/some_directory/

"編集可能" aka -eは、インポートメカニズムをリダイレクトして、このディレクトリにソースファイルをロードします。代わりに、現在の正確なファイルをインストール環境のライブラリにコピーします。これは、開発者のマシンで動作の違いを引き起こす可能性もあります。必ずコードをテストしてください!pip以外のツールもありますが、pipを導入ツールとしてお勧めします:)

また、モジュール(単一の「.py」ファイル)の代わりにfoo「パッケージ」(を含むディレクトリ__init__.py)を作成したいのですが、「パッケージ」と「モジュール」の両方をルート名前空間にロードでき、モジュールは名前空間をネストできます。これは、「1つ上のディレクトリに相対的に」インポートする場合に役立ちます。

some_directory/
    foo/
        __init__.py
    setup.py

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    packages=['foo'],
)

私も作るのが好きfoo/__main__.py、これはPythonは例えば、モジュールとしてパッケージを実行することができますpython3 -m foo実行されますfoo/__main__.pyよう__main__

some_directory/
    foo/
        __init__.py
        __main__.py  # `if __name__ == "__main__":`  lives here, `def main():` too!
    setup.py

#!/usr/bin/env python3
# setup.py

import setuptools

setuptools.setup(
    name="foo",
    ...
    packages=['foo'],
    ...
    entry_points={
        'console_scripts': [
            # "foo" will be added to the installing-environment's text mode shell, eg `bash -c foo`
            'foo=foo.__main__:main',
        ]
    },
)

これをさらにいくつかのモジュールで具体化しましょう:基本的に、次のようなディレクトリ構造を持つことができます:

some_directory/
    bar.py           # `import bar`
    foo/
        __init__.py  # `import foo`
        __main__.py
        baz.py       # `import foo.baz
        spam/           
            __init__.py  # `import foo.spam`
            eggs.py      # `import foo.spam.eggs`
    setup.py

setup.py 通常、以下のようなソースコードに関するメタデータ情報を保持します。

  • 「install_requires」という名前のインストールに必要な依存関係
  • パッケージ管理に使用する名前(install / uninstall "name")。fooハイフンの代わりにアンダースコアを使用するのが一般的ですが、これは、私たちのケースでは、プライマリPythonパッケージ名と一致することをお勧めします。
  • ライセンス情報
  • 成熟度タグ(アルファ/ベータ/など)、
  • オーディエンスタグ(開発者、機械学習など)、
  • 1ページのドキュメントコンテンツ(READMEなど)
  • シェル名(bashのようなユーザーシェルで入力する名前、またはスタートメニューのようなグラフィカルユーザーシェルで見つける名前)、
  • このパッケージがインストール(およびアンインストール)するPythonモジュールのリスト
  • 事実上の「テストの実行」エントリポイント python ./setup.py test

ソースモジュールが開発マシンにインストールされている場合、その拡張性は非常に高く、c拡張機能をその場でコンパイルすることもできます。毎日の例では、PYPAサンプルリポジトリのsetup.pyをお勧めします

ビルドアーティファクト(ほぼ同一のコンピューターを実行するためのコードのコピーなど)をリリースする場合、requirements.txtファイルは、正確な依存関係情報をスナップショットする一般的な方法です。ここで、「install_requires」は、最大互換バージョン。ただし、ターゲットマシンはほとんど同じであるので、Pythonプレフィックス全体のtarballを作成することを強くお勧めします。これは扱いにくいかもしれませんが、ここで説明するには詳細すぎます。pip install--targetオプション、またはリードのvirtualenv別名venvを確認してください。

例に戻る

ファイルを1つ上のディレクトリにインポートする方法:

foo / spam / eggs.pyから、foo / bazからのコードが必要な場合は、絶対的な名前空間で要求することができます。

import foo.baz

今後、他の相対baz実装を使用して、eggs.pyを他のディレクトリに移動する機能を予約したい場合は、次のような相対インポートを使用できます。

import ..baz

-5

Pythonはモジュラーシステムです

Pythonはファイルシステムに依存しない

Pythonコードを確実にロードするには、そのコードをモジュールに入れ、そのモジュールをPythonのライブラリにインストールします。

インストールされたモジュールは常にトップレベルの名前空間からロードできます import <name>


ここに公式に利用できる素晴らしいサンプルプロジェクトがあります:https : //github.com/pypa/sampleproject

基本的には、次のようなディレクトリ構造にすることができます。

the_foo_project/
    setup.py  

    bar.py           # `import bar`
    foo/
      __init__.py    # `import foo`

      baz.py         # `import foo.baz`

      faz/           # `import foo.faz`
        __init__.py
        daz.py       # `import foo.faz.daz` ... etc.

あなた宣言してくださいsetuptools.setup()ではsetup.py

公式の例:https : //github.com/pypa/sampleproject/blob/master/setup.py

私たちの場合、おそらくエクスポートbar.pyしたいと思います、そしてfoo/__init__.py私の簡単な例:

setup.py

#!/usr/bin/env python3

import setuptools

setuptools.setup(
    ...
    py_modules=['bar'],
    packages=['foo'],
    ...
    entry_points={}, 
        # Note, any changes to your setup.py, like adding to `packages`, or
        # changing `entry_points` will require the module to be reinstalled;
        # `python3 -m pip install --upgrade --editable ./the_foo_project
)

これで、モジュールをpythonライブラリーにインストールできます。pipを使用するとthe_foo_project、編集モードでPythonライブラリにインストールできるため、リアルタイムで作業できます

python3 -m pip install --editable=./the_foo_project

# if you get a permission error, you can always use 
# `pip ... --user` to install in your user python library

これで、任意のpythonコンテキストから、共有py_modulesおよびパッケージをロードできます

foo_script.py

#!/usr/bin/env python3

import bar
import foo

print(dir(bar))
print(dir(foo))

2
で作業している間は常にモジュールをインストールしますpip install --edit foo。ほとんどの場合、virtualenv内にインストールします。インストールするつもりのないモジュールを書くことはほとんどありません。私が知りたいことを誤解した場合。
ThorSummoner 2016年

また、toxのようなvenv-auto-creationテストスイートを使用することは、editable卵のリンクとインストールされたpythonモジュールがすべての点でまったく同じではないため、非常に役立つことにも言及する必要があります。たとえば、編集可能なモジュールに新しい名前空間を追加すると、パスルックアップで見つかりますが、それがsetup.pyファイルでエクスポートされていない場合、パッケージ化/インストールされません。ユースケースをテストしてください:)
ThorSummoner
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.