別のフォルダからファイルをインポートする


1407

次のフォルダ構造があります。

application/app/folder/file.py

にある別のPythonファイルのfile.pyからいくつかの関数をインポートしたい

application/app2/some_folder/some_file.py

私はもう試した

from application.app.folder.file import func_name

他にもさまざまな試みがありましたが、これまでは適切にインポートすることができませんでした。これどうやってするの?



公式ドキュメントを読んだことで、とても助かりました!docs.python.org/3/reference/...
KavinラジュS

回答:


1444

デフォルトではできません。ファイルをインポートするとき、Pythonは現在のディレクトリ、エントリポイントスクリプトが実行されているディレクトリ、およびsys.pathパッケージインストールディレクトリなどの場所を含む(実際にはこれより少し複雑ですが、ほとんどの場合をカバーします)だけを検索します。

ただし、実行時にPythonパスに追加できます。

# some_file.py
import sys
# insert at 1, 0 is the script path (or '' in REPL)
sys.path.insert(1, '/path/to/application/app/folder')

import file

356
sys.path.append('/path/to/application/app/folder')きれいですimo
pseudosudo

387
@pseudosudo:はい、そうですが、最初に挿入すると、名前が競合する場合にパスが他のパス(組み込みパスを含む)の前に検索されることが保証されます。
Cameron

8
@kreativitea-をsys.path返すのlistではなく、を返すので、をa dequeに変換しlistdeque戻すことはばかげています。
ArtOfWarfare 2013年

37
フォルダ内の.pyファイルを管理するためのpythonicな方法と考えられていますか?疑問に思っています...なぜデフォルトでサポートされていないのですか?それは... 1つのディレクトリにすべての.pyファイルを維持しても意味がありません
オフィール

49
@Ofir:いいえ、これはきれいなpythonicソリューションではありません。一般に、パッケージ(ディレクトリツリーに基づく)を使用する必要があります。この回答は、尋ねられた質問に固有のものであり、何らかの理由で多数の賛成票を集め続けています。
Cameron

709

何も問題ありません:

from application.app.folder.file import func_name

folderも含まれていることを確認してください__init__.py。これにより、パッケージとして含めることができます。なぜ他の回答がについて語っているのかわかりませんPYTHONPATH


47
これは、変更PYTHONPATHが必要な場合をカバーしていないためです。あなたは同じレベルに2つのフォルダがあるとしましょう:ABAを持ってい__init.py__ます。B内から何かをインポートしてみてくださいA
msvalkon 2014年

32
init.pyor __init__.pyファイルの中身は何ですか?
Lorem Ipsum Dolor 2015年

48
@Xinyang空のファイルである可能性があります。その存在はPythonにディレクトリをパッケージとして扱うように伝えます。
ジェイ2015年

9
もちろん、この回答は、applicationおよびappがすでにパッケージであることを前提としています(つまり、すでに__init__.py両方に含まれています)。追加の結果__init__.pyにもfolderapplication.app.folder(サブ)になったパッケージあなたがアクセスすることができ、そこから、モジュール application.app.folder.fileのシンボル、func_name今インポートすることができます
Yiboヤン

30
私が何をしようとしても、これはうまくいきません。「兄弟」ディレクトリからインポートしたいので、1つ上に1つ下に移動します。親を含むすべてに__ init __.pyがあります。これはpython 3固有ですか?
dasWesen 2017年

111

質問のように、モジュールが並列の場所にある場合:

application/app2/some_folder/some_file.py
application/app2/another_folder/another_file.py

この短縮形は、1つのモジュールを他のモジュールから見えるようにします。

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

24
注意点:これは、インポートスクリプトが含まれているディレクトリから実行されている限り機能します。そうでない場合、スクリプトが実行される他のディレクトリの親ディレクトリがパスに追加され、インポートは失敗します。
カールスミス

14
これを回避するために、ファイルの親ディレクトリを取得できますsys.path.append(os.path.dirname(os.path.abspath(__file__)))
Rahul

それは私にとってはうまくいきませんでした- cli/foo.pyコマンドラインから実行できるように、親に戻るためにそこに追加のdirnameを追加する必要がありましたimport cli.bar
RCross

2
@Rahul、あなたのソリューションはインタラクティブなシェルでは機能しません
towi_parallelism

ルートフォルダー(アプリケーションフォルダーなど)から実行する場合は、おそらくsys.path.append('.')を使用してモジュールをインポートすることで問題ありませんfrom app2.some_folder.some_file import your_function。別の方法としてpython3 -m app2.another_folder.another_file、ルートフォルダーから実行することもできます。
中毒

68

最初に sysをname-file.pyにインポートします

 import sys

次に、name-file.pyにフォルダーパスを追加します。

sys.path.insert(0, '/the/folder/path/name-package/')

3番目のサブディレクトリに__ init __.pyという名前の空のファイルを作成します(これはPythonにパッケージであることを通知します)

  • name-file.py
  • 名前パッケージ
    • __ init __.py
    • name-module.py

4番目に、name-file.pyのフォルダー内にモジュールをインポートします。

from name-package import name-module

5
name-folderがname-file.pyのすぐ下にあるので、これはsys.path.insert-command なしでも機能するはずです。そのため、名前フォルダーが任意の場所に配置されている場合でもこのソリューションが機能する場合、答えは疑問を残します。
バスティアン

55

アドホックな方法は、ドキュメントに記載されている環境変数PYTHONPATHを使用することだと思います:Python2Python3

# Linux & OSX
export PYTHONPATH=$HOME/dirWithScripts/:$PYTHONPATH

# Windows
set PYTHONPATH=C:\path\to\dirWithScripts\;%PYTHONPATH%

ちょっと待って、myScriptsをファイル名に置き換えますか?
ウラジミールプーチン

4
いいえ、.pyファイルへのディレクトリのパス
Ax3l

1
残念ながら、Anacondaを使用している場合、内部ではPYTHONPATHは実際には使用されないため、これは機能しません。
information_interchange

anacondaの(最近の)変更については、ワークフローと回避策のコメントについては、このSOを参照してください:stackoverflow.com/questions/17386880/…一般的に、インポートディレクトリをハッキングするのではなく、小さなパッケージをビルドしてインストールします。
Ax3l

47

ここでの答えは明確さに欠けています、これはPython 3.6でテストされています

このフォルダー構造では:

main.py
|
---- myfolder/myfile.py

myfile.py内容はどこにありますか:

def myfunc():
    print('hello')

のインポート文main.pyは次のとおりです。

from myfolder.myfile import myfunc
myfunc()

これはhelloと出力します。


9
Linux(y)でmyfolderにinit .py(空)設定ファイルを追加するとうまくいきました
Vincent

7
@Vincentはどういう意味__init__.pyですか?
mrgloom 2018

2
確かに@mrgloom
ヴィンセント

3
何らかの理由で、追加__init__.pyが機能しません。Ubuntu 18でPy 3.6.5を使用しています。Pycharmでは機能しますが、ターミナルでは機能しません
Crearo Rotar

9
これは、現在の作業ディレクトリとは異なるファイルツリーのブランチからファイルをインポートするかどうかを尋ねる質問とはまったく関係ありません。
アレクサンダーロッサ

45

あなたの問題は、Pythonがこのディレクトリを探してこのファイルを見つけていないことです。Pythonディレクトリではなく、現在のディレクトリについて話していることを指定する必要があります。

これを行うには、これを変更します。

from application.app.folder.file import func_name

これに:

from .application.app.folder.file import func_name

ドットを追加すると、Pythonディレクトリではなく、このフォルダーでアプリケーションフォルダーを探すことになります。


2
これが私を修正したものです
Phi

32

私が知っ__init__.pyていることから、インポートしたい関数のフォルダに直接ファイルを追加すると仕事ができます。


7
他のディレクトリを含めたいスクリプトがすでにsys.pathにある場合のみ
Ax3l

2
sys.path.append(tools_dir)はWindowsで使用し、__init__.py' file in my directory tools_dir を追加する必要はありません`
herve-guerin

25

Python 3.4以降では、ソースファイルから直接インポートできます(ドキュメントへのリンク)。これは最も簡単な解決策ではありませんが、完全性のためにこの回答を含めています。

ここに例があります。最初に、インポートするファイルの名前foo.py

def announce():
    print("Imported!")

上記のファイルをインポートするコードは、ドキュメントの例に大きく影響を受けています。

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

foo = module_from_file("foo", "/path/to/foo.py")

if __name__ == "__main__":
    print(foo)
    print(dir(foo))
    foo.announce()

出力:

<module 'foo' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

変数名、モジュール名、およびファイル名は一致する必要がないことに注意してください。このコードはまだ機能します:

import importlib.util

def module_from_file(module_name, file_path):
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module

baz = module_from_file("bar", "/path/to/foo.py")

if __name__ == "__main__":
    print(baz)
    print(dir(baz))
    baz.announce()

出力:

<module 'bar' from '/path/to/foo.py'>
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'announce']
Imported!

プログラムによるモジュールのインポートはPython 3.1で導入され、モジュールのインポート方法をより詳細に制御できます。詳細については、ドキュメントを参照してください。


11
誰かがこれを理解しようとしたかどうかはわかりませんが、複雑すぎると思います。
Dan

23

Linuxのpython3で私のために働いた

import sys  
sys.path.append(pathToFolderContainingScripts)  
from scriptName import functionName #scriptName without .py extension  

6
sys.path.append("/home/linux/folder/")—ショートカットを使用しないでください。例"~/folder/"
daGo

22

Pythonの相対インポートを試してください。

from ...app.folder.file import func_name

すべての先行ドットは、現在のディレクトリから始まる階層の別の上位レベルです。


問題?これがうまくいかない場合は、おそらく、多くの落とし穴の相対的なインポートが原因で少しビットを取得しています。詳細については、回答とコメントをお読みください: __init__.pyでも「非パッケージでの相対インポートの試行」を修正する方法

ヒント:__init__.pyすべてのディレクトリレベルにあります。python -m application.app2.some_folder.some_file最上位ディレクトリから実行する(.pyを省く)か、PYTHONPATHに最上位ディレクトリを含める必要がある場合があります。ふew!


22

私は同じ課題に直面しました、特に複数のファイルをインポートするとき、これが私がそれをどうにかして克服した方法です。

import os, sys

from os.path import dirname, join, abspath
sys.path.insert(0, abspath(join(dirname(__file__), '..')))

from root_folder import file_name

2
通常のインポートとは異なる点を説明できれば、答えはより役に立ちますか?
not2qubit

1
/path/dir1/__init__.pyと/path/dir1/mod.pyがありました。dir1.modからの/path/some.pyのインポート機能が動作しました。/path/dir2/some.pyにある場合、上記の回答をファイルの先頭にコピーして貼り付けた後でのみ機能しました。私が持っているすべてのPythonプロジェクトが/ path /にあるわけではないので、パスを編集したくありませんでした。
jwal

19

考えるapplicationあなたのpythonプロジェクトのルートディレクトリとして、空の作成__init__.pyでは、ファイルapplicationappおよびfolderフォルダを。次に、some_file.py次のように変更してfunc_nameの定義を取得します。

import sys
sys.path.insert(0, r'/from/root/directory/application')

from application.app.folder.file import func_name ## You can also use '*' wildcard to import all the functions in file.py file.
func_name()

sys.path.insert(0、r '/ from / root / directory')
Bolaka

18

絶対パスを指定してsys.path.appendを使用することは、アプリケーションを他の環境に移動するときに理想的ではありません。現在の作業ディレクトリはスクリプトの呼び出し方法に依存するため、相対パスを使用しても常に機能するとは限りません。

アプリケーションのフォルダー構造は固定されているため、os.pathを使用して、インポートするモジュールの完全パスを取得できます。たとえば、これが構造の場合:

/home/me/application/app2/some_folder/vanilla.py
/home/me/application/app2/another_folder/mango.py

そして、「mango」モジュールをインポートするとします。あなたはvanilla.pyで次のことをすることができます:

import sys, os.path
mango_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
+ '/another_folder/')
sys.path.append(mango_dir)
import mango

もちろん、mango_dir変数は必要ありません。

これがどのように機能するかを理解するには、この対話型セッションの例を見てください。

>>> import os
>>> mydir = '/home/me/application/app2/some_folder'
>>> newdir = os.path.abspath(os.path.join(mydir, '..'))
>>> newdir
    '/home/me/application/app2'
>>> newdir = os.path.abspath(os.path.join(mydir, '..')) + '/another_folder'
>>> 
>>> newdir
'/home/me/application/app2/another_folder'
>>> 

os.pathのドキュメントを確認してください。


13

これはWindowsで機能します

# some_file.py on mainApp/app2 
import sys
sys.path.insert(0, sys.path[0]+'\\app2')

import some_file

10

私はかなり特別です。WindowsでPythonを使用しています。

WindowsとLinuxの両方で、相対パスと絶対パスの両方が機能しますsys.path(複数のPCと異なるメインディレクトリでスクリプトを使用するため、相対パスが必要です)。

そして、両方のWindowsを使用している場合\/、ファイル名のセパレータとして使用することができ、もちろん、あなたが二重にする必要があり\、Pythonの文字列に
いくつかの有効な例を:

sys.path.append('c:\\tools\\mydir')
sys.path.append('..\\mytools')
sys.path.append('c:/tools/mydir')
sys.path.append('../mytools')

(注:Linux互換で書き込みやWindowsエクスプローラへのコピーが簡単であるため、「Windowsネイティブ」ではない場合、イベント/よりも便利だと思います\


4
os.path.join( 'tools'、 'mydir')
Corey Goldberg

7

特定のパスからモジュールをロードする目的がカスタムモジュールの開発中に支援することである場合、カスタムモジュールのルートを指すテストスクリプトの同じフォルダーにシンボリックリンクを作成できます。このモジュール参照は、そのフォルダーで実行されるスクリプトに対して同じ名前でインストールされている他のモジュールよりも優先されます。

Linuxでこれをテストしましたが、シンボリックリンクをサポートする最新のOSで動作するはずです。

このアプローチの利点の1つは、独自のローカルSVCブランチの作業コピーにあるモジュールをポイントできるため、開発サイクル時間を大幅に簡略化し、さまざまなバージョンのモジュールを管理する障害モードを減らすことができることです。


7

私の場合、インポートするクラスがありました。私のファイルは次のようになりました:

# /opt/path/to/code/log_helper.py
class LogHelper:
    # stuff here

メインファイルにコードを含めました:

import sys
sys.path.append("/opt/path/to/code/")
from log_helper import LogHelper

1
@ not2qubit sysは回答にインポートされませんでした。
ウォルター、

7

同じ質問に何度も遭遇したので、解決策を共有したいと思います。

Pythonバージョン:3.X

次のソリューションは、Pythonバージョン3.Xでアプリケーションを開発する人を対象としています。これは、2020年1月1日以降、Python 2がサポートされていないためです

プロジェクトの構造

Python 3では__init__.pyImplicit Namespace Packagesのため、プロジェクトのサブディレクトリは必要ありません。Python 3.3以降のパッケージでは、init .pyは不要かを参照してください。

Project 
├── main.py
├── .gitignore
|
├── a
|   └── file_a.py
|
└── b
    └── file_b.py

問題文

ではfile_b.py、クラスAfile_a.pyフォルダーaの下にインポートします。

ソリューション

#1迅速だが汚い方法

現在新しいプロジェクトを開発しているようにパッケージをインストールしない場合

を使用しtry catchてエラーかどうかを確認します。コード例:

import sys
try:
    # The insertion index should be 1 because index 0 is this file
    sys.path.insert(1, '/absolute/path/to/folder/a')  # the type of path is string
    # because the system path already have the absolute path to folder a
    # so it can recognize file_a.py while searching 
    from file_a import A
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

#2パッケージをインストールする

アプリケーションをインストールすると(この投稿では、インストールのチュートリアルは含まれていません)

あなたは簡単にできます

try:
    from __future__ import absolute_import
    # now it can reach class A of file_a.py in folder a 
    # by relative import
    from ..a.file_a import A  
except (ModuleNotFoundError, ImportError) as e:
    print("{} fileure".format(type(e)))
else:
    print("Import succeeded")

幸せなコーディング!


詳細は絶対輸入
WYスー

3

次のファイルリストaを使用pip install aして、ユーザーにインストールしてほしいプロジェクトに取り組んでいました。

.
├── setup.py
├── MANIFEST.in
└── a
    ├── __init__.py
    ├── a.py
    └── b
        ├── __init__.py
        └── b.py

setup.py

from setuptools import setup

setup (
  name='a',
  version='0.0.1',
  packages=['a'],
  package_data={
    'a': ['b/*'],
  },
)

MANIFEST.in

recursive-include b *.*

a / init .py

from __future__ import absolute_import

from a.a import cats
import a.b

a / a.py

cats = 0

a / b / init .py

from __future__ import absolute_import

from a.b.b import dogs

a / b / b.py

dogs = 1

次のディレクトリから次を実行してモジュールをインストールしましたMANIFEST.in

python setup.py install

次に、ファイルシステム上のまったく異なる場所から、/moustache/armwrestle実行できました:

import a
dir(a)

これにより、意図したとおり、実際にa.cats0に等しく、a.b.dogs実際に1 に等しいことが確認されました。


2

単にを実行する代わりにimport ...、次のようにします。

from <MySubFolder> import <MyFile>

MyFileはMySubFolder内にあります。


1

f5を押してPythonシェルを更新するか、「実行」->「モジュールの実行」に移動できます。この方法では、ファイルから何かを読み取るためにディレクトリを変更する必要はありません。Pythonは自動的にディレクトリを変更します。しかし、Pythonシェルの別のディレクトリにある別のファイルを操作する場合は、キャメロンが以前に言ったように、sysのディレクトリを変更できます。


1

そのため、IDEを右クリックし、新しいIDEを追加して、folderなぜそこからインポートできないのか疑問に思っていました。後で、右クリックしてPythonパッケージを作成する必要があることに気付きました。従来のファイルシステムフォルダーではありません。または、__init__.py他の回答で言及されているように、(Pythonにファイルシステムフォルダーをパッケージとして処理させる)を追加する検死メソッド。誰かがこのルートに行った場合に備えて、ここにこの回答を追加します。


1

importlibを使用して、次のような文字列を使用してフォルダーからモジュールをインポートするモジュールをインポートできます。

import importlib

scriptName = 'Snake'

script = importlib.import_module('Scripts\\.%s' % scriptName)

この例には、上記のコードであるmain.pyがあり、次にScriptsというフォルダーがあり、scriptName変数を変更することにより、このフォルダーから必要なものを呼び出すことができます。次にscript、このモジュールへの参照に使用できます。たとえばHello()、Snakeモジュールで呼び出された関数がある場合、次のようにしてこの関数を実行できます。

script.Hello()

私はこれをPython 3.6でテストしました


0

私はこれらの問題を何度も経験しました。私はこの同じページにたくさん来ました。最後の問題ではserver、固定ディレクトリからを実行する必要がありましたが、デバッグするときはいつでも、異なるサブディレクトリから実行したいと思っていました。

import sys
sys.insert(1, /path) 

異なるモジュールでは異なる* .csvを読み取る必要があったため、私にとってはうまくいきませんでしたではすべて同じディレクトリにあるファイルを。

結局、私にとってうまくいったのはpythonicではなかったと思いますが、

デバッグしたいモジュールの上部を使用しif __main__ ました通常のパスとは異なるパスから実行される、。

そう:

# On top of the module, instead of on the bottom
import os
if __name__ == '__main__':
    os.chdir('/path/for/the/regularly/run/directory')
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.