現在のディレクトリより上のディレクトリにあるファイルのクラスを継承したい。
そのファイルを比較的インポートすることは可能ですか?
現在のディレクトリより上のディレクトリにあるファイルのクラスを継承したい。
そのファイルを比較的インポートすることは可能ですか?
回答:
from ..subpkg2 import mod
Pythonのドキュメントごと:パッケージ階層内では、インポートステートメントのドキュメントにあるように、2つのドットを使用します。
インポートするモジュールを指定するときに、モジュールの絶対名を指定する必要はありません。モジュールまたはパッケージが別のパッケージに含まれている場合、パッケージ名を言及しなくても、同じトップパッケージ内で相対インポートを行うことができます。指定したモジュールまたはパッケージで先頭のドットを使用すると、
from
正確な名前を指定せずに現在のパッケージ階層を上に移動する高さを指定できます。先頭の1つのドットは、インポートを行うモジュールが存在する現在のパッケージを意味します。2つのドットは、1つのパッケージレベルを意味します。3つのドットは2レベル上にあります。したがってfrom . import mod
、pkg
パッケージ内のモジュールから実行すると、インポートされpkg.mod
ます。from ..subpkg2 import mod
内から実行するpkg.subpkg1
と、インポートされますpkg.subpkg2.mod
。相対インポートの仕様はPEP 328に含まれています。
PEP 328は、絶対/相対インポートを扱います。
import sys
sys.path.append("..") # Adds higher directory to python modules path.
@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
sys.path
され、同じモジュールを異なる名前で使用できるようになり、対応するすべてのバグが発生する可能性があります。pypyのautopath.pyまたはツイストの_preamble.pyは、ディレクトリを上方向にたどりながら最上位パッケージを識別する検索条件を使用して解決します。
sys.path.remove(pathYouJustAdded)
この新しいパスを保持しないようにするために、必要なインポート後に何かをしたい場合があります。
序文:私は以前の回答を大幅に書き直して、人々をpythonのエコシステムに容易に移行できるようにしたいと考えています。うまくいけば、pythonのインポートシステムを使用してすべての人に成功の最高の変化をもたらします。
これは、パッケージ内の相対的なインポートをカバーします。これは、OPの質問に対する最も可能性の高いケースだと思います。
これが、次のように記述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
これが、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
通常、以下のようなソースコードに関するメタデータ情報を保持します。
foo
ハイフンの代わりにアンダースコアを使用するのが一般的ですが、これは、私たちのケースでは、プライマリPythonパッケージ名と一致することをお勧めします。python ./setup.py test
ソースモジュールが開発マシンにインストールされている場合、その拡張性は非常に高く、c拡張機能をその場でコンパイルすることもできます。毎日の例では、PYPAサンプルリポジトリのsetup.pyをお勧めします
ビルドアーティファクト(ほぼ同一のコンピューターを実行するためのコードのコピーなど)をリリースする場合、requirements.txtファイルは、正確な依存関係情報をスナップショットする一般的な方法です。ここで、「install_requires」は、最大互換バージョン。ただし、ターゲットマシンはほとんど同じであるので、Pythonプレフィックス全体のtarballを作成することを強くお勧めします。これは扱いにくいかもしれませんが、ここで説明するには詳細すぎます。pip install
の--target
オプション、またはリードのvirtualenv別名venvを確認してください。
例に戻る
foo / spam / eggs.pyから、foo / bazからのコードが必要な場合は、絶対的な名前空間で要求することができます。
import foo.baz
今後、他の相対baz
実装を使用して、eggs.pyを他のディレクトリに移動する機能を予約したい場合は、次のような相対インポートを使用できます。
import ..baz
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
私の簡単な例:
#!/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およびパッケージをロードできます
#!/usr/bin/env python3
import bar
import foo
print(dir(bar))
print(dir(foo))
pip install --edit foo
。ほとんどの場合、virtualenv内にインストールします。インストールするつもりのないモジュールを書くことはほとんどありません。私が知りたいことを誤解した場合。
editable
卵のリンクとインストールされたpythonモジュールがすべての点でまったく同じではないため、非常に役立つことにも言及する必要があります。たとえば、編集可能なモジュールに新しい名前空間を追加すると、パスルックアップで見つかりますが、それがsetup.pyファイルでエクスポートされていない場合、パッケージ化/インストールされません。ユースケースをテストしてください:)