親フォルダーからのモジュールのインポート


625

Python 2.5を実行しています。

これは私のフォルダツリーです:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(私__init__.pyは各フォルダにもありますが、読みやすくするためにここでは省略しています)

nibモジュール内からモジュールをインポートするにはどうすればよいlifeですか?sys.pathをいじる必要なしにそれが可能であることを望んでいます。

注:実行中のメインモジュールはptdraftフォルダー内にあります。


1
PYTHONPATH設定は何ですか?
S.Lott、2009

2
ロス:私はそこを見ました。どうすればいいですか?私はすでに持ってい__init__.pyます。S.Lott:確認方法がわかりません...
Ram Rachum、2009

4
シェルから$ PYTHONPATHをエコーし​​ます。インポートsys; Python内からsys.pathを出力します。 docs.python.org/tutorial/...
S.Lott

@FlipMcF Googleはバブル検索エンジンであるため、この結果がかなり高いという事実は重要ではありません。さらに重要なのは、非バブル検索エンジンであるDuckDuckGoもこれを非常に高くランク付けしているという事実です。
ArtOfWarfare

3
すべてsys.pathまたはPYTHONPATH回答をスキップして、np8の優れた回答を確認することを強くお勧めします。はい、それは長い読書です。はい、大変な作業のようです。しかし、それが実際に問題を正しくそしてきれいに解決する唯一の答えです。
2018

回答:


118

問題は、モジュールが親ディレクトリにあるなどの問題とは関係がないようです。

を含むディレクトリptdraftをPYTHONPATH に追加する必要があります

あなたはそれがあなたとimport nib一緒に働いたと言いました、それはおそらくあなたがptdraftそれ自身(その親ではなく)をPYTHONPATHに追加したことを意味します。


15
再利用されることのない多くのパッケージで作業している場合、すべてをpythonpathに追加する必要はありません。
Jason Cheng、

@JasonCheng:では、なぜパッケージなのですか?
デイビスヘリング

7
私にとって、この答えはうまくいきました。しかし、それはより明確にするために、手順はでありimport sys、その後sys.path.append("..\<parent_folder>")
BCJuan

603

相対インポートを使用できます(python> = 2.5):

from ... import nib

(Python 2.5の新機能)PEP 328:絶対インポートと相対インポート

編集:別のドット「。」を追加しました 2つのパッケージを上る


177
ValueError: Attempted relative import in non-package
内部石2013年

18
@endolith:パッケージ内にある必要があります。つまり、init .pyファイルが必要です。
kirbyfan64sos 2013年

31
トップレベルのパッケージを超えて相対的なインポートを試みた
ユーザー

291
さらに正確に言うと、__init__.pyファイルが必要です。
カラデニズ2014

17
追加することがあるため、また、以下の答えを参照してください__init__.py:あなたがしなければならない唯一のものではありませんstackoverflow.com/questions/11536764/...
ベン・ファーマーは、

286

相対インポート(などfrom .. import mymodule)はパッケージでのみ機能します。現在のモジュールの親ディレクトリにある「mymodule」をインポートするには:

import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir) 

import mymodule

edit__file__属性は常に与えられるわけではありません。使用する代わりにos.path.abspath(__file__)、現在のファイルのファイル名(およびパス)を取得するためにinspectモジュールを使用することを提案しました


97
少し短いもの:sys.path.insert(1, os.path.join(sys.path[0], '..'))
JHolta 2013

8
挿入の代わりにsys.path.append()を回避する理由はありますか?
タイラー

2
@タイラー-どこかに問題がある可能性がありparentdirますがsys.path、で既に指定されているパスの1つに、「mymodule」という名前の別のモジュールがあります。リストのparentdir最初の要素としてを挿入sys.pathすると、モジュールparentdirがインポートされることが保証されます。
レミ

5
@JHoltaパッケージを扱っていない場合は、あなたのパッケージが最良のソリューションです。
Jonathon Reinhart 2013年

5
@JHolta素晴らしいアイデア。sys.path.insert(1, os.path.realpath(os.path.pardir))も動作します。
SpeedCoder5

177

兄弟パッケージからのインポートに関する質問にも同様の回答を投稿しました。こちらご覧いただけます

sys.pathハックなしのソリューション

概要

  • (例えば、1つのフォルダにコードをラップpackaged_stuff
  • setuptools.setup()setup.pyを使用する場所でcreate スクリプトを使用します。
  • パッケージを編集可能な状態でピップインストール pip install -e <myproject_folder>
  • 使用してインポート from packaged_stuff.modulename import function_name

セットアップ

質問と同じフォルダ構造を想定しています

.
└── ptdraft
    ├── __init__.py
    ├── nib.py
    └── simulations
        ├── __init__.py
        └── life
            ├── __init__.py
            └── life.py

.ルートフォルダーを呼び出しますC:\tmp\test_imports。私の場合はにあります。

手順

1)をsetup.pyルートフォルダに追加します

の内容はsetup.py簡単にできます

from setuptools import setup, find_packages

setup(name='myproject', version='1.0', packages=find_packages())

基本的に「すべて」setup.pyが機能します。これは最小限の実用例です。

2)仮想環境を使用する

仮想環境に慣れている場合は、仮想環境をアクティブにして、次の手順にスキップしてください。仮想環境の使用は絶対に必要なわけではありませんが、長期に見ると本当に役立ちます(複数のプロジェクトが進行中の場合)。最も基本的な手順は次のとおりです(ルートフォルダーで実行)

  • 仮想環境を作成する
    • python -m venv venv
  • 仮想環境をアクティブ化
    • . /venv/bin/activate(Linux)または./venv/Scripts/activate(Win)

詳細については、「python virtualenv tutorial」などのGoogleを使用してください。作成、アクティブ化、非アクティブ化以外のコマンドはおそらく必要ありません。

仮想環境を作成してアクティブ化すると、コンソールに仮想環境の名前が括弧内に表示されます。

PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>

3)プロジェクトを編集可能な状態でpipインストールする

を使用して最上位パッケージmyprojectをインストールしますpip。トリックは-e、インストールを行うときにフラグを使用することです。これにより、編集可能な状態でインストールされ、.pyファイルに対して行われたすべての編集は、インストールされたパッケージに自動的に含まれます。

ルートディレクトリで、次を実行します。

pip install -e . (ドットに注意してください、それは「現在のディレクトリ」を表します)

を使用してインストールされていることも確認できます pip freeze

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
  Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0

4)mainfolderすべてのインポートの前に追加してインポート

この例では、mainfolderはになりますptdraft。これには、他のモジュール名(python標準ライブラリまたはサードパーティモジュールから)と名前が競合しないという利点があります。


使用例

nib.py

def function_from_nib():
    print('I am the return value from function_from_nib!')

life.py

from ptdraft.nib import function_from_nib

if __name__ == '__main__':
    function_from_nib()

life.pyの実行

(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!

1
なぜこれが機能するのですか?それは舞台裏でPYTHONPATHをどうにかして変更していますか?
Homero Esmeraldo

2
また、なぜこれがsys.pathアプローチを使用するよりも優れているか、よりエレガントなのですか?
Homero Esmeraldo

5
@HomeroBarrocasSEsmeraldoいい質問ですね。PYTHONPATH env varは変更されていません。これはsite-packagesにインストールされます。これはすでにオンになってsys.pathおり、通常、エンドユーザーによってコードがインストールされます。これは、sys.pathハックよりも優れています(パスハックのカテゴリにPYTHONPATHを含めることができます)。これは、開発中のコードが他のユーザーと同じように動作することを意味するためです。対照的に、パス変更を使用する場合、インポートステートメントは別の方法で解決されます。
WIM

5
これは断然、私が読んだ最高のソリューションです。これにより、現在のディレクトリへのリンクが作成され、コードへのすべての更新が作業ディレクトリに直接反映されます。このエントリを削除する必要がある場合は、手動でeggファイルを削除し、dist-packages(pipを使用した場合はサイトパッケージ)のeasy-installからエントリを削除します。
Rakshit Kothari

2
なぜPythonインポートの頭痛をさらに複雑にするのですか?セットアップファイル、仮想環境、pipインストールを記述する必要がありますか?ああ、神様!
Emerson Xu

68

sys.pathにリストされている「モジュール検索パス」でOS依存パスを使用できます。したがって、次のように親ディレクトリを簡単に追加できます

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

親-親ディレクトリを追加する場合は、

sys.path.insert(0,'../..')

これはpython 2と3の両方で機能します。


6
これは、現在のディレクトリに相対的であり、メインスクリプトを含むディレクトリである必要はありません。
デイビスヘリング

57

PYTHONPATHにあなたのモジュールフォルダを追加すると、作業していない場合は、修正することができるのsys.pathの輸入へのモジュールのためのPythonインタプリタの検索は、どこのプログラムでリストをPythonのドキュメントは言います:

spamという名前のモジュールがインポートされると、インタープリターは最初にその名前の組み込みモジュールを検索します。見つからない場合は、sys.path変数で指定されたディレクトリのリストでspam.pyという名前のファイルを検索します。sys.pathは次の場所から初期化されます。

  • 入力スクリプトを含むディレクトリ(または現在のディレクトリ)。
  • PYTHONPATH(シェル変数PATHと同じ構文を持つディレクトリ名のリスト)。
  • インストール依存のデフォルト。

初期化後、Pythonプログラムはsys.pathを変更できます。実行中のスクリプトを含むディレクトリは、検索パスの先頭、標準ライブラリパスの前に配置されます。つまり、ライブラリディレクトリ内の同じ名前のモジュールの代わりに、そのディレクトリ内のスクリプトが読み込まれます。交換が意図されていない限り、これはエラーです。

これを知っていれば、プログラムで次のことができます。

import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append('/path/to/ptdraft/')

# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft

6
あなたの答えは良いですが、いつもうまくいくとは限らず、あまり移植性がありません。プログラムを新しい場所に移動した場合は、/path/to/ptdraft編集する必要があります。ファイルの現在のディレクトリを解決し、親フォルダーからそれをインポートするソリューションもあります。
Edward

@エドワードそれらのテクニックは何ですか?
Shuklaswag 2018

1
たとえば@Shuklaswagの場合、答えはstackoverflow.com/questions/714063/…です。
エドワード

50

Python 2についてはあまり知りません。
。Python3では、親フォルダーを次のように追加できます。

import sys 
sys.path.append('..')

...そして、そこからモジュールをインポートすることができます


13
これは、現在の作業ディレクトリが'..'、問題のモジュールのあるディレクトリにつながるような場合にのみ機能します。
user5359531 2017

31

答えはシンプルなので、小さなクロスプラットフォームでどのように機能するかを確認できます。
組み込みモジュール(ossysおよびinspect)のみを使用する
ため、Pythonはそのために設計されているため、どのオペレーティングシステム(OS)でも動作するはずです。

回答の短いコード-少ない行と変数

from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module  # Replace "my_module" here with the module name.
sys.path.pop(0)

これより少ないラインについて、を有する第二の行を交換import os.path as path, sys, inspect
追加inspect.の開始時getsourcefile(ライン3)と第1行を削除します。
-ただし、これによりすべてのモジュールがインポートされるため、より多くの時間、メモリ、リソースが必要になる可能性があります。

私の答えのコード(長いバージョン

from inspect import getsourcefile
import os.path
import sys

current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]

sys.path.insert(0, parent_dir)

import my_module  # Replace "my_module" here with the module name.

Stack Overflowの回答の例を使用しています。Pythonで現在
実行されているファイルのパスを取得するにはどうすればよいですか?
組み込みツールで実行中のコードのソース(ファイル名)を検索する。

from inspect import getsourcefile  
from os.path import abspath  

次に、どこからでもソースファイルを見つけたい場所を使用します。

abspath(getsourcefile(lambda:0))

私のコードはsys.pathPythonパスリストにファイルパスを追加します
、これはそのフォルダからインポートモジュールにはPythonを可能にするからです。

コードにモジュールをインポートした後 、その追加されたフォルダー に、プログラムで後でインポートされる別のモジュールと同じ名前のモジュールがある場合sys.path.pop(0)、新しい行で実行することをお勧めします。他のパスではなく、インポート前に追加されたリスト項目を削除する必要があります。 プログラムが他のモジュールをインポートしない場合は、プログラムが 終了した後(またはPythonシェルを再起動した後)に行われた編集のため、ファイルパスを削除しない方が安全です。



sys.path消えるです。

ファイル名変数に関する注意

私の回答では__file__、実行中の
コードのファイルパス/ファイル名を取得するために変数を使用していません。なぜなら、ここのユーザーは、それを信頼できないとしばしば説明しているからです。他の人が使用するプログラムの親フォルダーからモジュール
インポートするために使用しないでください

機能しない例(このスタックオーバーフローの質問からの引用):

• 一部のプラットフォームでは見つかりません完全なファイルパスではない場合があります

  • py2exe__file__属性はありませんが、回避策があります
  • IDLEから実行すると属性execute()がない__file__
  • OS X 10.6の入手先 NameError: global name '__file__' is not defined

1
これを行いsys.path.pop(0)、目的のモジュールをインポートした直後に新しいパスエントリを削除しました 。ただし、その後のインポートはその場所にまだ行きました。例えば、私が持っているapp/configapp/toolsapp/submodule/config。からsubmodule、私app/はインポートに挿入しtools、次に削除app/してインポートしようとしましたconfigが、app/config代わりに取得しますapp/submodule/config
user5359531 2017

toolsのインポートの1 configつが親ディレクトリからもインポートされていることがわかりました。それで、後でsys.path.pop(0); import configsubmoduleに入ることを期待して、 しようと思ったときapp/submodule/config、私は実際に得ていましたapp/config。明らかにPythonは、同じ名前のモジュールのキャッシュバージョンを実際にチェックするのではなく、同じ名前のモジュールを返しますsys.pathsys.pathこの場合、正しく変更されていましたが、同じ名前のモジュールが既にロードされているため、Pythonはそれをチェックしていませんでした。
user5359531 2017

これは私が抱えていた問題への正確な参照だと思います:docs.python.org/3/reference/import.html#the-module-cache
user5359531

5.3.1からの有用な情報モジュールのキャッシュ上のドキュメントのページ:インポート時に、モジュール名がでルックアップされsys.modules ... sys.modulesは書き込み可能です。キーを削除すると、指定されたモジュールのキャッシュエントリが無効になり、Pythonは次回のインポート時に新たに検索します。...ただし、モジュールオブジェクトへの参照を保持し、そのキャッシュを無効にしてから再インポートすると、2つのオブジェクトが異なることに注意してください。対照的に、importlib.reload()モジュールのコンテンツを再利用および再初期化します...
Edward

さらに短い:os.path.realpath(getsourcefile(lambda:0) + "/../..")。2つの親ディレクトリシンボルが追加された現在のソースファイルを取得します。私が使用していなかったos.path.sepとしてgetsourcefile使用して文字列を返すだった/としても、Windows上では。realpath親ディレクトリを指定するフルパス(この場合はファイル名、次に現在のディレクトリ)から2つのディレクトリエントリをポップオフします。
コバーン2017

28

親ディレクトリをsys.pathに含めるより一般的なソリューションを次に示します(私にとっては機能します)。

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

import os, sys\n sys.path.insert(0,os.path.pardir) 同じことですが、ソーター:)(コメントに改行はありません)
Anti Veeranna '23 / 09/23

@antiveeranna、使用するos.path.pardir場合、親のsys.path.insert()
実際の

1
この答えは、StackOverflowユーザーがよく言及している__file__ように、信頼できない可能性のある変数を使用します(常に完全なファイルパスではない、すべてのオペレーティングシステムで機能しないなど)。回答を含まないように変更すると、問題が少なくなり、相互互換性が高まります。詳細については、stackoverflow.com/ a/ 33532002/3787376を参照してください。
エドワード

23

スクリプトの親ディレクトリからパッケージをインポートするには、次の方法が機能することがわかりました。この例ではenv.pyapp.dbパッケージから関数をインポートします。

.
└── my_application
    └── alembic
        └── env.py
    └── app
        ├── __init__.py
        └── db
import os
import sys
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)

だから、素晴らしいワンライナー:sys.path.append(os.path.dirname(os.path.dirname(os.path.realpath(__file__))))
juzzlin

sys.path通常、まったく変更することはお勧めできません。あなたはいくつかの方法(必要例えばPYTHONPATHあなたのライブラリがにアクセスできるようにするための)のコードを(またはそうでなければ、ライブラリ本当にありません)。ずっとそれを使ってください!
デイビスヘリング

14

上記の解決策も問題ありません。この問題の別の解決策は

トップレベルのディレクトリから何かをインポートしたい場合。そして、

from ...module_name import *

また、親ディレクトリからモジュールをインポートする場合。そして、

from ..module_name import *

また、親ディレクトリからモジュールをインポートする場合。そして、

from ...module_name.another_module import *

これにより、必要に応じて特定のメソッドをインポートできます。


6
これは本来あるべきように見えますが、何らかの理由でsys.path.append上記のハックと同じように機能せず、このように自分のlibをインポートできません。これは私がグーグルを始める前に最初にやろうとしたことです:) ValueError: attempted relative import beyond top-level package
わかりました

10

私にとって、親ディレクトリにアクセスするための最も短くてお気に入りのonelinerは次のとおりです。

sys.path.append(os.path.dirname(os.getcwd()))

または:

sys.path.insert(1, os.path.dirname(os.getcwd()))

os.getcwd()は現在の作業ディレクトリの名前を返し、os.path.dirname(directory_name)は渡されたディレクトリのディレクトリ名を返します。

実際、私の意見では、Pythonプロジェクトアーキテクチャは、子ディレクトリのモジュールが親ディレクトリのモジュールを使用しない方法で実行する必要があります。このようなことが発生した場合は、プロジェクトツリーについて再考する価値があります。

別の方法は、親ディレクトリをPYTHONPATHシステム環境変数に追加することです。


2
(問題にハックを投げるのとは対照的に)プロジェクトを再構築する必要がある可能性を言及するための+1
semore_1267 '19

これは親を取得せず、現在を取得します
Ricky Levi

9

Jupyter Notebook内

Jupyter Notebookで作業している限り、この短い解決策が役立つ可能性があります。

%cd ..
import nib

それなしでも動作します __init__.pyファイルがます。

LinuxとWindows 7のAnaconda3でテストしました。


2
%cd -インポート後に追加しても意味がないので、ノートブックの現在のディレクトリは変更されません。
Dror


5

__init__.pyファイルを含むパッケージ環境にない場合、pathlibライブラリ(> = Python 3.4に含まれる)を使用すると、親ディレクトリのパスをPYTHONPATHに追加することが非常に簡潔かつ直感的になります。

import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))

init .py を使用してこの問題を回避することは可能ですか?
人工知能

4

過去の回答と同じようなスタイルですが、行数は少なくなります:P

import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)

ファイルはあなたが働いている場所を返します


私にとって、ファイルはパスを含まないファイル名です。「ipy filename.py」を使用して実行します。
Curtis Yallop、2014年

こんにちは@CurtisYallop上の例では、Pythonファイルがある[現在入っている]ファイルを含むディレクトリを追加しています。ファイル名を指定したos.path.dirnameを呼び出すと、ファイルのパスが返されます。明示的にファイルではなくパスにTHATを追加しています-HTH's :-)
YFP

__file__には常にパスとファイルが含まれていると想定しています。時々それはパスなしでファイル名だけを含む。
Curtis Yallop

@CurtisYallop-全然、私はファイルを想定していますファイル名であると私は、ファイルのパスを取得するにはos.path.dirname()を使用しています。これが機能しない例をお持ちですか?再現する手順が気に入っています
YFP

1
@CurtisYallop-いいえ、私は違います!私は言っています:print / _ / file / _ /は上の例の "file.py"のファイル名を提供します-次に、os.path.dirname()を使用してその完全なパスをプルできると言います。奇妙な場所から呼び出していて、そのリレーショナルが必要な場合は、osモジュールを介して作業ディレクトリを簡単に見つけることができます-Jeez!
YFP 2014年

1

ライブラリを操作します。nibと呼ばれるライブラリを作成し、setup.pyを使用してインストールし、サイトパッケージに常駐させて問題を解決します。作成したすべてのものを1つのパッケージに詰め込む必要はありません。それをバラバラに分解します。


1
あなたのアイデアは良いですが、モジュールをコードにバンドルすることを望む人もいるでしょう-おそらくそれを移植可能site-packagesにし、別のコンピューターで実行するたびにモジュールを置く必要がないようにするためです。
エドワード

0

Linuxシステムでは、「life」フォルダーからnib.pyファイルへのソフトリンクを作成できます。その後、次のようにインポートするだけです。

import nib
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.