相対パスからモジュールをインポートする


759

相対パスを指定してPythonモジュールをインポートするにはどうすればよいですか?

たとえば、dirFoocontains Foo.pyおよびdirBardirBarcontainsのBar.py場合、どのようにインポートBar.pyFoo.pyますか?

ここに視覚的な表現があります:

dirFoo\
    Foo.py
    dirBar\
        Bar.py

Fooを含めたいBarが、フォルダ階層の再構築はオプションではありません。



3
私の回答を確認してください。これはこれまでで最も完全なものです。たとえば、別のディレクトリまたは別のpythonスクリプトからスクリプトを呼び出す場合など、特別な場合には他のユーザーは機能しません。stackoverflow.com/questions/279237/…を
sorin

同様の問題があり、これを見つけて動作しました!! apt-get install python-profiler
ldcl289

5
誰かが静的にそれをしたいと思ってここに来た場合に備えて(私がやったように)、PYTHONPATH環境変数を設定することもできます
okaram

どちらの場合もLib / site.pyの指示に従うことをお勧めします
Avenida Gez

回答:


333

両方のディレクトリが実際のPythonパッケージである(__init__.pyファイルがその中にある)と仮定すると、スクリプトの場所に対して相対的にモジュールを含めるための安全なソリューションを次に示します。

スクリプトに一連のモジュールを含める必要があるため、これを実行したいと思います。私はこれをいくつかの製品のプロダクションで使用し、次のような多くの特別なシナリオで動作します。新しいインタープリターを開く代わりに、別のディレクトリから呼び出された、またはpython executeで実行されたスクリプト。

 import os, sys, inspect
 # realpath() will make your script run, even if you symlink it :)
 cmd_folder = os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]))
 if cmd_folder not in sys.path:
     sys.path.insert(0, cmd_folder)

 # Use this if you want to include modules from a subfolder
 cmd_subfolder = os.path.realpath(os.path.abspath(os.path.join(os.path.split(inspect.getfile( inspect.currentframe() ))[0],"subfolder")))
 if cmd_subfolder not in sys.path:
     sys.path.insert(0, cmd_subfolder)

 # Info:
 # cmd_folder = os.path.dirname(os.path.abspath(__file__)) # DO NOT USE __file__ !!!
 # __file__ fails if the script is called in different ways on Windows.
 # __file__ fails if someone does os.chdir() before.
 # sys.argv[0] also fails, because it doesn't not always contains the path.

おまけとして、このアプローチでは、システムにインストールされているモジュールの代わりにモジュールをPythonに使用させることができます。

警告!現在のモジュールがeggファイル内にあるときに何が起こっているのか本当にわかりません。それもおそらく失敗します。


5
これがどのように機能するかについての説明はありますか?私は同様の問題を抱えており、検索を実行する代わりにpythonモジュールDIRを強制するのが
大好きです

Win 7 Pro 64xおよびPython 2.7を実行すると、いくつかのエラーが発生します。1)インポートリストにインスペクションを追加する必要がありました。2)タプルの最初の値[0]は空の文字列です。2番目の[1]はファイル名を示します。私は最初がパスでなければならないことを推測しています...アイデアはありますか?
アダムルイス

2
サブフォルダを使用する場合は、次のように使用します。重大なバグが発生するため、前にサブフォルダを追加os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]) + "/subfolder")ないでくださいabspath
Maximilian

4
@ scr4ve代わりにos.path.join()を使用する必要がありますcmd_subfolder。ケース()を直接私の回答に追加してください。ありがとう!
ソリン

7
私はrealpathすでに絶対パスを生成しているので、必要ありませんabspath。またos.path.dirname、分割の代わりに使用して、索引付けを[0]廃止することもできます。行は次のようになりますos.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))
テッド

328

dirBarに__init__.pyファイルがあることを確認してください。これにより、ディレクトリがPythonパッケージに作成されます。


204
このファイルは完全に空にできることに注意してください。
Harley Holcombe

47
dirBarの親ディレクトリがsys.path存在しない場合__init__.pydirBarディレクトリ内に存在 してもあまり役に立ちません。
jfs 2008年

7
-1、追加__init.py__はディレクトリが既にsys.pathにある場合にのみ機能し、私の場合はそうではありませんでした。「ソーリン」(受け入れた)による解決は常に機能します。
Czarek Tomczak

12
「ディレクトリがすでにsys.pathにある場合」。完全に真実ですが、ディレクトリがsys.path質問に含まれていないとどうして推測できますか?おそらく、私たちが見たり知らなかったりした何かが省略されたのでしょうか?
S.Lott、2011年

4
これは「いいえ」の質問に対する回答です。初期化ファイルが存在するかどうかにかかわらず、これによってpythonがサブディレクトリを調べることはありません。どうして何百もの賛成票を得たのですか?
2017

261

通常のスクリプトとしてインポートされるように、サブディレクトリをPythonパスに追加することもできます。

import sys
sys.path.insert(0, <path to dirFoo>)
import Bar

6
それはあなたの答えは、相対パスを持つ作品は、見ていないことになりますstackoverflow.com/questions/279237/...
ボグダン

24
これ相対パスで機能します-相対パスは実行元のディレクトリに依存することを理解する必要があるだけで、クイックハッキング以外のソリューションとしては不十分です。
nobar 2012

12
あなたは次のようなことをすることができますsys.path.append(os.path.dirname(__file__) + "/relative/path/to/module")
Falko

またはsys.path.append(__name__ if __name__ != '__main__' else __loader__.fullname)
vim

1
sys.path.insert(0, <path to dirFoo>)他の場所に保存されている同じ名前のモジュールの前にこのモジュールをロードするため、使用を検討してください。
アントンタラセンコ2017年

117
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)

import mymodule

2
ディレクトリを上に移動する柔軟性があるので、これが好きです。
チャールズL.

21
os.path.join()(不完全な)ウィンドウで壊れる「/」で結合する代わりに使用する必要があります。
0xc0de 2012

18
これは信頼できません。これは、スクリプトが存在するディレクトリではなく、現在の作業ディレクトリに依存します。
jamesdlin 2014年

パスがまだパスにない場合にのみ追加したい場合があります。lib_path = os.path.abspath( '../ functions')lib_pathがsys.pathにない場合:sys.path.append(lib_path)
ブレント

@jamesdlinへの返信にいくつかの答えを組み合わせて:どうos.path.abspath(os.path.join(__file__,'..','lib'))ですか?
マシューデイビス

107

別のフォルダから.pyファイルをインポートするだけの簡単なことを行います。

次のようなディレクトリがあるとします。

lib/abc.py

次に、名前付きのlibフォルダーに空のファイルを保持します

__init__.py

そして使用します

from lib.abc import <Your Module name>

__init__.pyインポートモジュールの階層のすべてのフォルダーにファイルを保持します。


79

プロジェクトをこのように構成した場合:

src\
  __init__.py
  main.py
  dirFoo\
    __init__.py
    Foo.py
  dirBar\
    __init__.py
    Bar.py

次に、Foo.pyから次のことができるはずです。

import dirFoo.Foo

または:

from dirFoo.Foo import FooObject

トムのコメントによれば、これには、または検索パスをsrc介してフォルダにアクセスできる必要がありますsite_packages。また、彼が言及するように、__init__.py最初にそのパッケージ/ディレクトリにモジュールをインポートすると、は暗黙的にインポートされます。通常__init__.pyは、単に空のファイルです。


また、そのパッケージ内の最初のモジュールがインポートされるときにinit .pyがインポートされることにも言及してください。また、この例は、srcがsite_packages(または検索パス)にある場合にのみ機能します
Tom Leys

3
これは、私が探していた最も簡単なソリューションです。インポートするファイルが確実にサブディレクトリの1つにある場合、このソリューションは宝石です。
Deepak GM、

私は同じことを試みて失敗しました。何故かはわからない。ImportError:customMathという名前のモジュールはありません
Ming Li

9
なぜ誰かがFoo.py自体からFooをインポートしたいのですか?Bar.pyからのはずです。
bhaskarc 2015年

from dirFoo import Fooと言うFoo.bla()import dirFoo.Foo使用する場合は使用する必要がありますdirFoo.Foo.bla()-キャメルケースがなくてもかなり醜いです。
Cees Timmerman、2016年

45

最も簡単な方法は、sys.path.append()を使用することです。

ただし、impモジュールにも興味がある可能性があります。内部インポート機能へのアクセスを提供します。

# mod_name is the filename without the .py/.pyc extention
py_mod = imp.load_source(mod_name,filename_path) # Loads .py file
py_mod = imp.load_compiled(mod_name,filename_path) # Loads .pyc file 

これは、モジュールの名前がわからないときにモジュールを動的にロードするために使用できます。

過去にこれを使用して、ユーザーがアプリケーション固有の機能を備えたスクリプトを記述し、特定のディレクトリにスクリプトをドロップする、アプリケーションへのプラグインタイプのインターフェイスを作成しました。

また、これらの関数は役に立つかもしれません:

imp.find_module(name[, path])
imp.load_module(name, file, pathname, description)

ドキュメントでは、imp.load_sourceとimp.load_compiledは廃止されていると記載されています。代わりに、imp.find_moduleおよびimp.load_moduleをお勧めします。
amicitas '18 / 10/18

@amicitas、そのための参照を提供してもらえますか(私はそれを必要とし、私はpython 2.6を使用しています
。2.7の

@ 0xc0deこのステートメントは、python 2.7.3python 2.6.7の両方のimpモジュールのドキュメントにあります。これらの関数はpython 3.2のドキュメントにもないようです。
amicitas 2012

1
このようなPython 3.3でのソースファイルのインポートについては、「任意のPythonソースファイルインポートする」を参照してください(Python 3.3以降)-スタックオーバーフロー。ここのヒントをありがとう、ありがとう。
nealmcb 2014年


23

スクリプトを変更せずに最も簡単な方法は、PYTHONPATH環境変数を設定することです。sys.pathは次の場所から初期化されるためです。

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

ただ走れ:

export PYTHONPATH=/absolute/path/to/your/module

以下に示すように、sys.pathには上記のパスが含まれます。

print sys.path

['', '/absolute/path/to/your/module', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/python2.7/dist-packages/gst-0.10', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/ubuntu-sso-client', '/usr/lib/python2.7/dist-packages/ubuntuone-client', '/usr/lib/python2.7/dist-packages/ubuntuone-control-panel', '/usr/lib/python2.7/dist-packages/ubuntuone-couch', '/usr/lib/python2.7/dist-packages/ubuntuone-installer', '/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']

13

私の意見では、__ init __.pyをフォルダーに入れて、

from dirBar.Bar import *

既存のpythonパッケージと同じファイル名を使用すると問題が発生する可能性があるため、sys.path.append()の使用はお勧めしません。私はそれをテストしていませんが、あいまいになります。


奇妙なことですfrom dirBar.Bar import *が、うまくいきませんfrom dirBar.Bar import Bar。*が機能する理由を知っていますか?dirBar /に複数のファイルがあり、それらのいくつかだけを取得したい場合(ここに投稿したような方法を使用)
テスター

2
@テスター:を使用しfrom dirBar import Barます。
nobar 2012

@testerこれfromは、がソースを示し、その後のすべてimportがそのソースから取得するものだからです。from dirBar.Bar import Bar「ソースから、ソース自体をインポートする」という意味ですが、意味がありません。*しかし手段は、「私のソースからすべて与える」
FuriousFolder

11

Linuxユーザーのための簡単な方法

単にいじくり回していてデプロイメントの問題を気にしない場合は、シンボリックリンクを使用して(ファイルシステムがそれをサポートしている場合)、モジュールまたはパッケージを要求側モジュールのフォルダーに直接表示できます。

ln -s (path)/module_name.py

または

ln -s (path)/package_name

注:「モジュール」は.py拡張子を持つ任意のファイルであり、「パッケージ」はファイル__init__.py(空のファイルの場合もあります)を含む任意のフォルダーです。使用の観点から見ると、モジュールとパッケージは同じです。どちらも、importコマンドで要求されたときに含まれる「定義とステートメント」を公開します。

参照:http : //docs.python.org/2/tutorial/modules.html


10
from .dirBar import Bar

の代わりに:

from dirBar import Bar

別のdirBarがインストールされ、foo.pyリーダーを混乱させる可能性がある場合に備えて。


2
Windowsではこれを行うことができませんでした。これはLinux上ですか?
ガブリエル

1
Fooをインポートするスクリプトから動作します。つまり、main.pyはdirFoo.Fooをインポートします。Foo.pyをスクリプトとして実行しようとすると、失敗します。stackoverflow.com/questions/72852/…を
jgomo3

9

この場合、Bar.pyをFoo.pyにインポートするには、まずこれらのフォルダーを次のようにPythonパッケージに変換します。

dirFoo\
    __init__.py
    Foo.py
    dirBar\
        __init__.py
        Bar.py

次に、Foo.pyで次のようにします。

from .dirBar import Bar

名前空間をバーのようにしたい場合。何でも、または

from . import dirBar

名前空間のdirBar.Barが必要な場合。何でも。この2番目のケースは、dirBarパッケージの下にさらにモジュールがある場合に役立ちます。


7

__init__.pyファイルを追加します。

dirFoo\
    Foo.py
    dirBar\
        __init__.py
        Bar.py

次に、このコードをFoo.pyの先頭に追加します。

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

5
場合はdirBar、すでに(の存在により、PythonパッケージであるdirBar/__init__.py)、追加する必要はありませんdirBarにはsys.path無いですか、?import Barからの声明Foo.pyで十分です。
サンタ

5

相対sys.pathの例:

# /lib/my_module.py
# /src/test.py


if __name__ == '__main__' and __package__ is None:
    sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../lib')))
import my_module

この答えに基づいてます。


5

さて、あなたが言及したように、通常、メインスクリプトが実行される場所に関連するモジュールを含むフォルダーにアクセスしたいので、それらをインポートするだけです。

解決:

スクリプトD:/Books/MyBooks.pyといくつかのモジュール(oldies.pyなど)があります。サブディレクトリからインポートする必要がありますD:/Books/includes

import sys,site
site.addsitedir(sys.path[0] + '\\includes')
print (sys.path)  # Just verify it is there
import oldies

にを配置しprint('done')oldies.py、すべてが正常であることを確認します。sys.pathプログラムの起動時に初期化されるPython定義によって、このリストの最初の項目はpath[0]、Pythonインタープリターの呼び出しに使用されたスクリプトを含むディレクトリであるため、この方法は常に機能します。

スクリプトディレクトリが利用できない場合(たとえば、インタプリタがインタラクティブに呼び出される場合、またはスクリプトが標準入力から読み取られる場合)path[0]は、空の文字列で、Pythonに現在のディレクトリで最初にモジュールを検索するように指示します。の結果として挿入されたエントリの前にスクリプトディレクトリが挿入されていることに注意してくださいPYTHONPATH


1
私の代わりに2つのバックスラッシュ(すなわちの1スラッシュを使用する必要がありましたsite.addsitedir(sys.path[0]+'/includes'):私の最初の簡単なPythonプログラムのbreak_time.pyに) https://github.com/ltfschoen/PythonTest。私が使用しているシステム:MacOS v10.11.5、Python 2.7.12、IDLE IDE 2.7.12、Tk 8.5.9
Luke Schoen

4

単にあなたが使うことができます: from Desktop.filename import something

例:

ファイルはtest.pydirectory内の名前であり Users/user/Desktop、すべてをインポートします。

コード:

from Desktop.test import *

ただし__init__.py、そのディレクトリに" " という空のファイルを作成してください。


1
スター付きのインポートは推奨されません。参照:stackoverflow.com/questions/2386714/why-is-import-bad
axolotl

最初に書いた理由を知っimport somethingているので、* 基本的にRAMに
適さ

3

別の解決策は、py-requireパッケージをインストールしてから、以下を使用することです。Foo.py

import require
Bar = require('./dirBar/Bar')

URLは実際にはpypi.org/project/require.pyのようであり、Pipを介してインストールする必要があることに注意してください。
フラッシュシェリダン

1
@FlashSheridanいいえ、それは別のプロジェクトです。py-requireは誰も使用していないと確信しているので削除しましたが、この投稿については考えていませんでした。それでもrequire()関数が必要な場合は、私のNode.pyプロジェクトを確認してください:github.com/nodepy/nodepy
Niklas R

2

相対パスを使用して、1つ上のレベルからファイルをインポートする方法を次に示します。

基本的には、作業ディレクトリを1つ上のレベル(または任意の相対位置)に移動し、それをパスに追加してから、作業ディレクトリを元の場所に戻します。

#to import from one level above:
cwd = os.getcwd()
os.chdir("..")
below_path =  os.getcwd()
sys.path.append(below_path)
os.chdir(cwd)

1
私はここであなたの論理を理解していません。複雑
すぎます

0

私はpythonの経験がないので、私の言葉に誤りがあれば教えてください。ファイル階層が次のように配置されている場合:

project\
    module_1.py 
    module_2.py

module_1.py関数を定義してfunc_1()module_2.py

from module_1 import func_1

def func_2():
    func_1()

if __name__ == '__main__':
    func_2()

そしてあなたがpython module_2.pycmdで実行すると、func_1()定義したものを実行します。これが通常、同じ階層ファイルをインポートする方法です。しかし、あなたが書いfrom .module_1 import func_1たときmodule_2.py、Pythonインタープリターは言うでしょうNo module named '__main__.module_1'; '__main__' is not a package。したがって、これを修正するには、行った変更を保持し、両方のモジュールをパッケージに移動し、実行する呼び出し元として3番目のモジュールを作成しますmodule_2.py

project\
    package_1\
        module_1.py
        module_2.py
    main.py

main.py

from package_1.module_2 import func_2

def func_3():
    func_2()

if __name__ == '__main__':
    func_3()

しかし、我々は追加の理由.の前module_1ではmodule_2.py、我々はそれと実行をしない場合ということですmain.py、Pythonインタプリタは言うだろうNo module named 'module_1'、少しトリッキーだと、module_1.py右横にありますmodule_2.py。今、私は聞かせてfunc_1()module_1.py何か:

def func_1():
    print(__name__)

__name__誰がfunc_1を呼び出すかを記録します。これで、実行.前の状態が維持され、印刷されるのではなく、印刷されます。これは、呼び出し元がと同じ階層にあることを示します。つまり、それ自体と同じ階層にあることを意味します。したがって、ドットがない場合は、それ自体と同じ階層で認識されますが、は認識できますが、その「下」は認識できません。module_1main.pypackage_1.module_1module_1func_1()main.py.module_1module_2.pymain.pymodule_1package_1

それでは、少し複雑にしましょう。がconfig.iniあり、モジュールが「main.py」と同じ階層でそれを読み取る関数を定義している。

project\
    package_1\
        module_1.py
        module_2.py
    config.py
    config.ini
    main.py

そして、やむを得ない理由から、それをmodule_2.pyで呼び出す必要があるため、上位階層からインポートする必要があります。module_2.py

 import ..config
 pass

2つのドットは上位階層からのインポートを意味します(3つのドットは上位より上位にアクセスする、など)。実行するmain.pyと、インタプリタは次のように言いますValueError:attempted relative import beyond top-level package。ここの「トップレベルのパッケージ」はmain.pyです。理由だけでconfig.py横にあるmain.py、彼らは同じ階層にある、config.py「下」ではないmain.py、またはそれはによって「有鉛」ではありませんmain.py、それは超えているので、main.py。これを修正するには、最も簡単な方法は次のとおりです。

project\
    package_1\
        module_1.py
        module_2.py
    config.py
    config.ini
main.py

それはプロジェクトファイル階層の配置の原則と一致すると思います。異なる機能のモジュールを異なるフォルダーに配置し、一番上の呼び出し元を外側に置いておくだけで、好きなようにインポートできます。


-5

これも機能し、sysモジュールでは何よりもはるかに簡単です。

with open("C:/yourpath/foobar.py") as f:
    eval(f.read())

1
OPがパスをハードコーディングする場合は、とにかくそのパスをPYTHONPATHに挿入するだけで済みます。ポイントは、パスが他のどこかで壊れるので、パスをハードコードしない方法でそうしていると思います。
マシュー

-15

過度に用心深く呼んでください。しかし、ファイルが常にすべてのコンピューターの同じ場所にあると想定するのは危険なので、鉱山をよりポータブルにしたいと思います。個人的には、コードでファイルパスを最初に検索します。私はLinuxを使用しているので、私のように見えるでしょう:

import os, sys
from subprocess import Popen, PIPE
try:
    path = Popen("find / -name 'file' -type f", shell=True, stdout=PIPE).stdout.read().splitlines()[0]
    if not sys.path.__contains__(path):
        sys.path.append(path)
except IndexError:
    raise RuntimeError("You must have FILE to run this program!")

これらを一緒にパッケージ化する予定がない限り、それはもちろんです。しかし、その場合は、とにかく2つの個別のファイルは必要ありません。


11
超非効率です!
0xc0de 2012

1
相対パスを指定すると、ファイルは常にすべてのコンピューターの同じ場所に配置されます。
Sagar Hatekar
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.