質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • Python

    7994questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Pythonで他のディレクトリからプログラムをimportするやり方

受付中

回答 6

投稿 編集

  • 評価
  • クリップ 3
  • VIEW 16K+

jimmypage0311

score 14

Pythonで親ディレクトリの親ディレクトリのファイルをimportしたいのですが
以下のようなコードでは, 読み込める時と読み込めない時があります。

読み込めない時と読み込めない時の例ですが
今日読み込めたのにもかかわらず、次の日に読み込めなくなるということが以下のコードでは起こります。

import sys,os
sys.path.append('../../') # 親ディレクトリの親ディレクトリを読み込む

from ... import *  # ... : 親ディレクトリの親ディレクトリのフォルダ名, * : そのフォルダ内のimportしたいプログラム名

他におすすめのファイルの読み込み方法はあるでしょうか。

よろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • shimizukawa

    2017/02/10 12:24

    「読み込み」とはファイルをopen()で開くことではなく 「import したい」という意味ですよね?であれば、そのように質問を書いた方がよいです。あと、「読み込めるときと読み込めないときがある」というのは具体的に、「どうしたら、どうなった」のでしょうか?操作手順と結果を提示してください。

    キャンセル

  • jimmypage0311

    2017/02/10 17:26

    タイトル、質問を編集いたしましたのでよろしくお願いいたします。

    キャンセル

回答 6

+2

os.pathモジュールを使うのがおすすめです。
OSごとのパスの扱いの違いを吸収してくれます。

参考(具体的な使い方):[Python]ファイル/ディレクトリ操作

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

'../../'は、実行時のカレントディレクトリの親の親なので、実行時のカレントディレクトリがどこであるかによって成功したり失敗したりするんだと思います。

すでに回答がついていますが、スクリプトファイルの存在するディレクトリを基準にするように書き直す必要があります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

スクリプトファイルを基準にするならば、このような方法で親ディレクトリを取得できます。

from os import path, pardir

current_dir = path.abspath(path.dirname(__file__))  # スクリプトのディレクトリ
parent_dir = path.abspath(path.join(current_dir, pardir))  # スクリプトの親ディレクトリ
parent_parent_dir = path.abspath(path.join(parent_dir, pardir))  # 上記の親ディレクトリ

print(current_dir)
print(parent_dir)
print(parent_parent_dir)

ターミナルやJupyter notebook上では上記の方法はつかえないためご注意ください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

sys.path をスクリプト内で調整することはあまり推奨されません。
色々なところで使いたいライブラリを置いているディレクトリが固定で、そのライブラリをimportしたいのであれば、環境変数 PYTHONPATH を設定する方法があります。

ライブラリが /path/to/pythonfiles にあるとして、今編集しているスクリプトが /path/to/pythonfiles/sub/sub/current.py だとします。

環境変数を以下のように設定します。
(Mac, Linuxの場合)

export PYTHONPATH=/path/to/pythonfiles

(Windowsの場合)

set PYTHONPATH=/path/to/pythonfiles

この状態でプログラムcurrent.pyを実行すれば、current.pyがどこにっても、/path/to/pythonfiles以下にあるモジュールをimportできます。このときcurrent.pyのコード上でsys.path.appendは不要です。

なお、この方法でPYTHONPATHを設定しすぎると、環境がぐちゃぐちゃになっていくので、よく分からない内は複数のパスを設定するのはやめたほうがよいと思います。

ところで、先ほど説明した方法で環境変数を設定しても、シェルを閉じるとその設定は失われてしまいます。
OS起動時に自動的にこれを設定する方法については、各OSの話になるので省略します。


蛇足ですが、以下を実行するとPythonのライブラリパス(PYTHONPATH)が確認できます。

python -c "import sys;print(sys.path)"


普段使っている import os なども、上記で表示されるディレクトリのどこかに os.py があってそれが読み込まれているのが分かると思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

というようなディレクトリ構成で、各スクリプトは

# coding: utf-8
# pkg/subpkg1/hoge.py

from .piyo import *
from ..subpkg2.fuga import *
from ..foo import *
# coding: utf-8
# pkg/subpkg1/piyo.py

print('Hello, piyo.')
# coding: utf-8
# pkg/subpkg2/fuga.py

print('Hello, fuga.')
# coding: utf-8
# pkg/foo.py

print('Hello, foo.')

というような内容であった場合、

import 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」文のみで

import .piyo

というようには使えません。

あと、うちのlinuxではpython2では動きません。
上記のリファレンスの説明は、Python2.7のリファレンスにも書かれているので、使えると思うんですけどねぇ…。

このようにめんどくさい点はあるのだけど、こういう記述もできる、というぐらいには知っておいてもいいかと思います。


追記:
あれ、質問文を読み直したら、既に知ってるのかな?
だとしたら余計な回答かもしれませんが、どっちとも取れるので、一応書いておきますね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/10/05 20:33

    python3で実行してみました。
    一度目はうまく動くのですが、2回目以降は動作しません。
    各ディレクトリに__pycache__という新規のディレクトリが作成されそのなかに__pycache__が作成されたディレクトリにある.pyファイル名の.py拡張子部分が.cpython-36.pycに変換されたものが入っています。
    一旦pythonを終了してから再度pythonを立ち上げ実行するともう一度作動しますが、やはり2回目以降は何も表示されません。対策がわかればお教え下さい

    キャンセル

0

sys.path.appendを呼ぶのは良い手とはいえません。
sys.pathは全てのモジュールが参照するリストですので、他のモジュールに影響を及ぼす可能性があります。
例えば、あるモジュールを外すと今まで動いていたモジュールが、途端にimport Errorが発生する、挙動が変わってしまうなどです。

私は相対インポートで解決が良いと思います。

コードを拝見すると既に相対インポートされていますが、さらにsys.path.appendしているという事は相対インポートで上手く動作していないのだと推察します。
おそらくトップレベルスクリプト(起動スクリプト)よりも上の階層のモジュールをインポートしているのではないでしょうか?
相対インポートは、トップレベルスクリプトよりも上の階層はインポートできません。

対策としては起動のためだけのスクリプトを階層の一番上に置き、今までトップスクリプトとして扱ってきたものをモジュールとしてimportしてはどうでしょうか?
これならば相対インポートで上の階層のモジュールをインポートすることができます。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    7994questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。