相対パスを指定してPythonモジュールをインポートするにはどうすればよいですか?
たとえば、dirFoocontains Foo.pyおよびdirBar、dirBarcontainsのBar.py場合、どのようにインポートBar.pyしFoo.pyますか?
ここに視覚的な表現があります:
dirFoo\
Foo.py
dirBar\
Bar.py
Fooを含めたいBarが、フォルダ階層の再構築はオプションではありません。
相対パスを指定してPythonモジュールをインポートするにはどうすればよいですか?
たとえば、dirFoocontains Foo.pyおよびdirBar、dirBarcontainsのBar.py場合、どのようにインポートBar.pyしFoo.pyますか?
ここに視覚的な表現があります:
dirFoo\
Foo.py
dirBar\
Bar.py
Fooを含めたいBarが、フォルダ階層の再構築はオプションではありません。
回答:
両方のディレクトリが実際の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ファイル内にあるときに何が起こっているのか本当にわかりません。それもおそらく失敗します。
os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]) + "/subfolder")しないでくださいabspath。
cmd_subfolder。ケース()を直接私の回答に追加してください。ありがとう!
realpathすでに絶対パスを生成しているので、必要ありませんabspath。またos.path.dirname、分割の代わりに使用して、索引付けを[0]廃止することもできます。行は次のようになりますos.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))
dirBarに__init__.pyファイルがあることを確認してください。これにより、ディレクトリがPythonパッケージに作成されます。
sys.path存在しない場合__init__.py、dirBarディレクトリ内に存在 してもあまり役に立ちません。
__init.py__はディレクトリが既にsys.pathにある場合にのみ機能し、私の場合はそうではありませんでした。「ソーリン」(受け入れた)による解決は常に機能します。
sys.path質問に含まれていないとどうして推測できますか?おそらく、私たちが見たり知らなかったりした何かが省略されたのでしょうか?
通常のスクリプトとしてインポートされるように、サブディレクトリをPythonパスに追加することもできます。
import sys
sys.path.insert(0, <path to dirFoo>)
import Bar
sys.path.append(os.path.dirname(__file__) + "/relative/path/to/module")
sys.path.append(__name__ if __name__ != '__main__' else __loader__.fullname)
sys.path.insert(0, <path to dirFoo>)他の場所に保存されている同じ名前のモジュールの前にこのモジュールをロードするため、使用を検討してください。
import os
import sys
lib_path = os.path.abspath(os.path.join(__file__, '..', '..', '..', 'lib'))
sys.path.append(lib_path)
import mymodule
os.path.join()(不完全な)ウィンドウで壊れる「/」で結合する代わりに使用する必要があります。
os.path.abspath(os.path.join(__file__,'..','lib'))ですか?
別のフォルダから.pyファイルをインポートするだけの簡単なことを行います。
次のようなディレクトリがあるとします。
lib/abc.py
次に、名前付きのlibフォルダーに空のファイルを保持します
__init__.py
そして使用します
from lib.abc import <Your Module name>
__init__.pyインポートモジュールの階層のすべてのフォルダーにファイルを保持します。
プロジェクトをこのように構成した場合:
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は、単に空のファイルです。
from dirFoo import Fooと言うFoo.bla()。import dirFoo.Foo使用する場合は使用する必要がありますdirFoo.Foo.bla()-キャメルケースがなくてもかなり醜いです。
最も簡単な方法は、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)
これは関連するPEPです。
http://www.python.org/dev/peps/pep-0328/
特に、dirFooはdirBarから上のディレクトリであると仮定します...
dirFoo \ Foo.pyで:
from ..dirBar import Bar
スクリプトを変更せずに最も簡単な方法は、PYTHONPATH環境変数を設定することです。sys.pathは次の場所から初期化されるためです。
ただ走れ:
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']
私の意見では、__ init __.pyをフォルダーに入れて、
from dirBar.Bar import *
既存のpythonパッケージと同じファイル名を使用すると問題が発生する可能性があるため、sys.path.append()の使用はお勧めしません。私はそれをテストしていませんが、あいまいになります。
from dirBar.Bar import *が、うまくいきませんfrom dirBar.Bar import Bar。*が機能する理由を知っていますか?dirBar /に複数のファイルがあり、それらのいくつかだけを取得したい場合(ここに投稿したような方法を使用)
from dirBar import Barます。
fromは、がソースを示し、その後のすべてimportがそのソースから取得するものだからです。from dirBar.Bar import Bar「ソースから、ソース自体をインポートする」という意味ですが、意味がありません。*しかし手段は、「私のソースからすべて与える」
単にいじくり回していてデプロイメントの問題を気にしない場合は、シンボリックリンクを使用して(ファイルシステムがそれをサポートしている場合)、モジュールまたはパッケージを要求側モジュールのフォルダーに直接表示できます。
ln -s (path)/module_name.py
または
ln -s (path)/package_name
注:「モジュール」は.py拡張子を持つ任意のファイルであり、「パッケージ」はファイル__init__.py(空のファイルの場合もあります)を含む任意のフォルダーです。使用の観点から見ると、モジュールとパッケージは同じです。どちらも、importコマンドで要求されたときに含まれる「定義とステートメント」を公開します。
from .dirBar import Bar
の代わりに:
from dirBar import Bar
別のdirBarがインストールされ、foo.pyリーダーを混乱させる可能性がある場合に備えて。
相対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
さて、あなたが言及したように、通常、メインスクリプトが実行される場所に関連するモジュールを含むフォルダーにアクセスしたいので、それらをインポートするだけです。
解決:
スクリプト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。
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
単にあなたが使うことができます: from Desktop.filename import something
例:
ファイルは
test.pydirectory内の名前でありUsers/user/Desktop、すべてをインポートします。
コード:
from Desktop.test import *
ただし__init__.py、そのディレクトリに" " という空のファイルを作成してください。
import somethingているので、* 基本的にRAMに
別の解決策は、py-requireパッケージをインストールしてから、以下を使用することです。Foo.py
import require
Bar = require('./dirBar/Bar')
require()関数が必要な場合は、私のNode.pyプロジェクトを確認してください:github.com/nodepy/nodepy
相対パスを使用して、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)
私は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
それはプロジェクトファイル階層の配置の原則と一致すると思います。異なる機能のモジュールを異なるフォルダーに配置し、一番上の呼び出し元を外側に置いておくだけで、好きなようにインポートできます。
過度に用心深く呼んでください。しかし、ファイルが常にすべてのコンピューターの同じ場所にあると想定するのは危険なので、鉱山をよりポータブルにしたいと思います。個人的には、コードでファイルパスを最初に検索します。私は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つの個別のファイルは必要ありません。