Pythonで親ディレクトリの親ディレクトリのファイルをimportしたいのですが
以下のようなコードでは, 読み込める時と読み込めない時があります。
読み込めない時と読み込めない時の例ですが
今日読み込めたのにもかかわらず、次の日に読み込めなくなるということが以下のコードでは起こります。
Python
1import sys,os 2sys.path.append('../../') # 親ディレクトリの親ディレクトリを読み込む 3 4from ... import * # ... : 親ディレクトリの親ディレクトリのフォルダ名, * : そのフォルダ内のimportしたいプログラム名
他におすすめのファイルの読み込み方法はあるでしょうか。
よろしくお願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2017/02/10 08:26
回答6件
0
sys.path
をスクリプト内で調整することはあまり推奨されません。
色々なところで使いたいライブラリを置いているディレクトリが固定で、そのライブラリをimportしたいのであれば、環境変数 PYTHONPATH を設定する方法があります。
ライブラリが /path/to/pythonfiles にあるとして、今編集しているスクリプトが /path/to/pythonfiles/sub/sub/current.py だとします。
環境変数を以下のように設定します。
(Mac, Linuxの場合)
bash
1export PYTHONPATH=/path/to/pythonfiles
(Windowsの場合)
Cmd
1set PYTHONPATH=/path/to/pythonfiles
この状態でプログラムcurrent.pyを実行すれば、current.pyがどこにっても、/path/to/pythonfiles以下にあるモジュールをimportできます。このときcurrent.pyのコード上でsys.path.appendは不要です。
なお、この方法でPYTHONPATHを設定しすぎると、環境がぐちゃぐちゃになっていくので、よく分からない内は複数のパスを設定するのはやめたほうがよいと思います。
ところで、先ほど説明した方法で環境変数を設定しても、シェルを閉じるとその設定は失われてしまいます。
OS起動時に自動的にこれを設定する方法については、各OSの話になるので省略します。
蛇足ですが、以下を実行するとPythonのライブラリパス(PYTHONPATH)が確認できます。
Bash
1python -c "import sys;print(sys.path)"
普段使っている import os なども、上記で表示されるディレクトリのどこかに os.py があってそれが読み込まれているのが分かると思います。
投稿2017/02/10 08:35
総合スコア1847
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
os.pathモジュールを使うのがおすすめです。
OSごとのパスの扱いの違いを吸収してくれます。
参考(具体的な使い方):[Python]ファイル/ディレクトリ操作
投稿2017/02/10 03:11
編集2017/02/10 03:13総合スコア38339
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
相対importという手段もあります。
インポートするモジュールを指定するとき、そのモジュールの絶対名 (absolute name) を指定する必要はありません。モジュールやパッケージが他のパッケージに含まれている場合、共通のトップパッケージからそのパッケージ名を記述することなく相対インポートすることができます。 from の後に指定されるモジュールやパッケージの先頭に複数個のドットを付けることで、正確な名前を指定することなしに現在のパッケージ階層からいくつ上の階層へ行くかを指定することができます。先頭のドットが 1 つの場合、 import をおこなっているモジュールが存在する現在のパッケージを示します。 3 つのドットは 2 つ上のレベルを示します。なので、 pkg パッケージの中のモジュールで from . import mod を実行すると、 pkg.mod をインポートすることになります。 pkg.subpkg1 の中から from ..subpkg2 import mod を実行すると、 pkg.subpkg2.mod をインポートします。相対インポートの仕様は PEP 328 に含まれています。
例えば、
$ find . -name '*.py' ./pkg/subpkg1/piyo.py ./pkg/subpkg1/hoge.py ./pkg/subpkg2/fuga.py ./pkg/foo.py
というようなディレクトリ構成で、各スクリプトは
python
1# coding: utf-8 2# pkg/subpkg1/hoge.py 3 4from .piyo import * 5from ..subpkg2.fuga import * 6from ..foo import * 7
python
1# coding: utf-8 2# pkg/subpkg1/piyo.py 3 4print('Hello, piyo.') 5
python
1# coding: utf-8 2# pkg/subpkg2/fuga.py 3 4print('Hello, fuga.') 5
python
1# coding: utf-8 2# pkg/foo.py 3 4print('Hello, foo.') 5
というような内容であった場合、
python
1import pkg.subpkg1.hoge
というスクリプトを実行すると、
Hello, piyo. Hello, fuga. Hello, foo.
と、ちゃんとimportが実行されます。
ただし、注意が必要です。
まず、相対importが使えるのはモジュールの中のみです。
importされたスクリプトでないと、使えません。
例えば、上記のhoge.pyを、
python3 pkg/subpkg1/hoge.py
と直接してしてして実行すると、
Traceback (most recent call last): File "pkg/subpkg1/hoge.py", line 3, in <module> from .piyo import * SystemError: Parent module '' not loaded, cannot perform relative import
と怒られます。
あと、使えるのは「from - import」文のみで
python
1import .piyo
というようには使えません。
あと、うちのlinuxではpython2では動きません。
上記のリファレンスの説明は、Python2.7のリファレンスにも書かれているので、使えると思うんですけどねぇ…。
このようにめんどくさい点はあるのだけど、こういう記述もできる、というぐらいには知っておいてもいいかと思います。
追記:
あれ、質問文を読み直したら、既に知ってるのかな?
だとしたら余計な回答かもしれませんが、どっちとも取れるので、一応書いておきますね。
投稿2017/02/10 14:57
編集2017/02/10 15:11総合スコア3536
0
スクリプトファイルを基準にするならば、このような方法で親ディレクトリを取得できます。
python
1from os import path, pardir 2 3current_dir = path.abspath(path.dirname(__file__)) # スクリプトのディレクトリ 4parent_dir = path.abspath(path.join(current_dir, pardir)) # スクリプトの親ディレクトリ 5parent_parent_dir = path.abspath(path.join(parent_dir, pardir)) # 上記の親ディレクトリ 6 7print(current_dir) 8print(parent_dir) 9print(parent_parent_dir)
ターミナルやJupyter notebook上では上記の方法はつかえないためご注意ください。
投稿2017/02/10 03:28
総合スコア720
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
sys.path.append
を呼ぶのは良い手とはいえません。
sys.path
は全てのモジュールが参照するリストですので、他のモジュールに影響を及ぼす可能性があります。
例えば、あるモジュールを外すと今まで動いていたモジュールが、途端にimport Error
が発生する、挙動が変わってしまうなどです。
私は相対インポートで解決が良いと思います。
コードを拝見すると既に相対インポートされていますが、さらにsys.path.append
しているという事は相対インポートで上手く動作していないのだと推察します。
おそらくトップレベルスクリプト(起動スクリプト)よりも上の階層のモジュールをインポートしているのではないでしょうか?
相対インポートは、トップレベルスクリプトよりも上の階層はインポートできません。
対策としては起動のためだけのスクリプトを階層の一番上に置き、今までトップスクリプトとして扱ってきたものをモジュールとしてimport
してはどうでしょうか?
これならば相対インポートで上の階層のモジュールをインポートすることができます。
投稿2017/06/01 02:31
編集2017/06/01 02:33総合スコア930
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。