web-dev-qa-db-ja.com

親フォルダからモジュールをインポートする

私はPython 2.5を実行しています。

これは私のフォルダツリーです:

ptdraft/
  nib.py
  simulations/
    life/
      life.py

(各フォルダーに__init__.pyもあります。読みやすくするためにここでは省略しています)

nibモジュールの中からlifeモジュールをインポートするにはどうすればいいですか?私はそれがsys.pathに手を加えることなく行うことが可能であることを願っています。

注:実行されているメインモジュールはptdraftフォルダーにあります。

473
Ram Rachum

問題は、モジュールが親ディレクトリにあること、またはそのようなことに関連していないようです。

ptdraftを含むディレクトリをPYTHONPATHに追加する必要があります。

あなたはimport nibがあなたと一緒に働いたと言いました、それはおそらくあなたがptdraft自身(その親ではない)をPYTHONPATHに追加したことを意味します。

98
hasen

相対インポート(python> = 2.5)を使うことができます。

from ... import nib

(Python 2.5の新機能)PEP 328:絶対インポートと相対インポート

_ edit _ :別のドット「。」を追加しました2つ上がる

530
f3lix

相対インポート(from .. import mymoduleのように)はパッケージ内でのみ機能します。現在のモジュールの親ディレクトリにある 'mymodule'をインポートするには:

import os,sys,inspect
currentdir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
parentdir = os.path.dirname(currentdir)
sys.path.insert(0,parentdir) 

import mymodule

edit __file__属性は常に与えられるわけではありません。 os.path.abspath(__file__)を使用する代わりに、現在のファイルのファイル名(およびパス)を取得するためにinspectモジュールを使用することをお勧めします

220
Remi

兄弟パッケージからのインポートに関する質問に対しても同様の回答を投稿しました。ご覧になれます こちら 。以下はPython 3.6.5、(Anaconda、conda 4.5.1)、Windows 10 machineでテストされています。 。

Sys.pathハックなしの解決策

セットアップ

質問と同じフォルダ構造を想定しています

.
└── ptdraft
    ├── __init__.py
    ├── nib.py
    └── simulations
        ├── __init__.py
        └── life
            ├── __init__.py
            └── life.py

私は.をルートフォルダと呼び、私の場合はC:\tmp\test_importsにあります。

ステップ

1)setup.pyをルートフォルダに追加してください。

setup.pyの内容は単純に

from setuptools import setup, find_packages

setup(name='myproject', version='1.0', packages=find_packages())

基本的に "any" setup.pyが動くでしょう。これはほんの最小限の例です。

2)仮想環境を利用する

仮想環境に慣れている場合は、アクティブにして次のステップに進みます。仮想環境の使用は絶対必須ではありませんが、本当に help長い目で見ればあなたは外出中です(進行中のプロジェクトが複数ある場合)。最も基本的な手順は次のとおりです(ルートフォルダで実行)。

  • 仮想環境を作成する
    • python -m venv venv
  • 仮想環境を有効にする
    • . /venv/bin/activate(Linux)または./venv/Scripts/activate(Win)

これについてもっと知るためには、単に "python virtual env tutorial"かそれに類似したものをグーグルで出しなさい。作成、有効化、無効化以外のコマンドは必要ないでしょう。

仮想環境を作成してアクティブにすると、コンソールから仮想環境の名前が括弧内に表示されます。

PS C:\tmp\test_imports> python -m venv venv
PS C:\tmp\test_imports> .\venv\Scripts\activate
(venv) PS C:\tmp\test_imports>

3)編集可能な状態でプロジェクトをpipインストールします

myprojectを使用して最上位パッケージpipをインストールします。トリックはインストールをするとき-eフラグを使うことです。これにより編集可能な状態でインストールされ、.pyファイルに加えられたすべての編集は自動的にインストールされたパッケージに含まれます。

ルートディレクトリで、次のコマンドを実行します。

pip install -e .(ドットに注意してください、それは "現在のディレクトリ"を表します)

pip freezeを使用してインストールされていることもわかります。

(venv) PS C:\tmp\test_imports> pip install -e .
Obtaining file:///C:/tmp/test_imports
Installing collected packages: myproject
  Running setup.py develop for myproject
Successfully installed myproject
(venv) PS C:\tmp\test_imports> pip freeze
myproject==1.0

4)すべてのインポートにmainfolderを追加してインポートする

この例では、mainfolderptdraftになります。これには、他のモジュール名(python標準ライブラリや他社製モジュールからの名前)と名前が衝突しないという利点があります。


使用例

nib.py

def function_from_nib():
    print('I am the return value from function_from_nib!')

life.py

from ptdraft.nib import function_from_nib

if __== '__main__':
    function_from_nib()

実行中のlife.py

(venv) PS C:\tmp\test_imports> python .\ptdraft\simulations\life\life.py
I am the return value from function_from_nib!
56
np8

モジュールフォルダをPYTHONPATHに追加してもうまくいかない場合は、Pythonインタープリタがインポートするモジュールを検索するプログラムの sys.path リストを変更できます。 python documentation

spam という名前のモジュールがインポートされると、インタプリタはまずその名前の組み込みモジュールを探します。見つからない場合は、変数sys.pathで指定されたディレクトリのリスト内で spam.py という名前のファイルを検索します。 sys.pathは次の場所から初期化されます。

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

初期化後、Pythonプログラムは sys.path を変更できます。実行されているスクリプトを含むディレクトリは、標準ライブラリパスよりも先に検索パスの先頭に配置されます。つまり、ライブラリディレクトリ内の同じ名前のモジュールの代わりに、そのディレクトリ内のスクリプトが読み込まれます。置き換えが意図されていない限り、これはエラーです。

これを知って、あなたはあなたのプログラムの中で以下のことをすることができます:

import sys
# Add the ptdraft folder path to the sys.path list
sys.path.append('/path/to/ptdraft/')

# Now you can import your module
from ptdraft import nib
# Or just
import ptdraft
48
Ricardo Murillo

sys.path にリストされている "module search path"でOS依存のパスを使うことができます。したがって、次のように簡単に親ディレクトリを追加できます。

import sys
sys.path.insert(0,'..')

親 - 親ディレクトリを追加したい場合は、

sys.path.insert(0,'../..')
38
Shinbero

Python 2についてあまり知らないでください。
python 3では、親フォルダは次のように追加することができます。

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

...そして、そこからモジュールをインポートすることができます

33
Rob Ellenbroek

簡単な答えを以下に示しますので、小さくてクロスプラットフォームな仕組みを確認できます。
組み込みモジュール(ossysおよびinspect)のみを使用するため、動作するはずです
Pythonはそのために設計されているため、任意のオペレーティングシステム(OS)で。

回答の短いコード-少ない行と変数

from inspect import getsourcefile
import os.path as path, sys
current_dir = path.dirname(path.abspath(getsourcefile(lambda:0)))
sys.path.insert(0, current_dir[:current_dir.rfind(path.sep)])
import my_module  # Replace "my_module" here with the module name.
sys.path.pop(0)

これより少ない行については、2行目をimport os.path as path, sys, inspectに置き換え、
getsourcefile(3行目)の先頭にinspect.を追加し、最初の行を削除します。
-ただし、これはすべてのモジュールをインポートするため、より多くの時間、メモリ、リソースが必要になる場合があります。

私の答えのコード(longer version

from inspect import getsourcefile
import os.path
import sys

current_path = os.path.abspath(getsourcefile(lambda:0))
current_dir = os.path.dirname(current_path)
parent_dir = current_dir[:current_dir.rfind(os.path.sep)]

sys.path.insert(0, parent_dir)

import my_module  # Replace "my_module" here with the module name.

Stack Overflow answerの例を使用します 現在のパスを取得する方法
Pythonで実行されたファイル?
組み込みツールで実行中のコードのソース(ファイル名)を見つけます。

from inspect import getsourcefile  
from os.path import abspath  

次に、使用するソースファイルを検索する場所で使用します。

abspath(getsourcefile(lambda:0))

私のコードは、sys.pathpythonパスリストにファイルパスを追加します
これにより、Pythonがそのフォルダーからモジュールをインポートできるためです。

モジュールをコードにインポートした後、sys.path.pop(0)を新しい行で実行することをお勧めします
追加されたフォルダーに、インポートされた別のモジュールと同じ名前のモジュールがある場合
プログラムの後半。他のパスではなく、インポートの前に追加されたリスト項目を削除する必要があります。
プログラムが他のモジュールをインポートしない場合、ファイルパスを削除しない方が安全です。
プログラムが終了(またはPythonシェルを再起動)した後、sys.pathに対して行った編集はすべて消えます。

ファイル名変数に関する注意

私の答えは、__file__変数を使用して実行中のファイルパス/ファイル名を取得しません
コードは、ここのユーザーがしばしばunreliableと記述しているためです。あなたはそれを使うべきではありません
他の人が使用するプログラムの親フォルダーからモジュールをインポートするための。

動作しない例( this Stack Overflowの質問からの引用):

•it できません 一部のプラットフォームで見つかりました•時々 ファイルのフルパスではありません

  • py2exeには__file__属性はありませんが、回避策があります
  • execute()を指定してIDLEから実行すると、__file__属性はありません
  • OS X 10.6でNameError: global name '__file__' is not definedが表示されます
29
Edward

これがsys.pathに親ディレクトリを含むより一般的な解決策です(私のために働きます):

import os.path, sys
sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir))
26
Mike

私にとって、親ディレクトリにアクセスするための最短かつ最も好きなonelinerは、次のとおりです。

sys.path.append(os.path.dirname(os.getcwd()))

または

sys.path.insert(1, os.path.dirname(os.getcwd()))

os.getcwd()は現在の作業ディレクトリの名前を返し、os.path.dirname(directory_name)は渡されたディレクトリのディレクトリ名を返します。

実際、私の意見では、Pythonプロジェクトのアーキテクチャーは、子ディレクトリーからのモジュールが親ディレクトリーからのモジュールを使用しないようにするべきです。このようなことが起こった場合、プロジェクトツリーについて再考する価値があります。

もう1つの方法は、PYTHONPATHシステム環境変数に親ディレクトリを追加することです。

9
zviad

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

7
Andong Zhan

__init__.pyファイルがあるパッケージ環境にいないときは、pathlibライブラリ(> = Python 3.4に含まれています)はPYTHONPATHに親ディレクトリのパスを追加することを非常に簡潔で直感的にします。

import sys
from pathlib import Path
sys.path.append(str(Path('.').absolute().parent))
6
itmatters

上記の解決策も大丈夫です。この問題に対する別の解決策は

最上位ディレクトリから何かインポートしたい場合。その後、

from ...module_name import *

また、親ディレクトリから任意のモジュールをインポートしたい場合。その後、

from ..module_name import *

また、親ディレクトリから任意のモジュールをインポートしたい場合。その後、

from ...module_name.another_module import *

これにより、必要に応じて特定のメソッドをインポートできます。

6
Ravin Gupta

過去の答えと同じ種類のスタイル - しかしより少ない行で:P

import os,sys
parentdir = os.path.dirname(__file__)
sys.path.insert(0,parentdir)

fileは作業中の場所を返します

3
YFP

ライブラリを操作します。 nibという名前のライブラリを作り、setup.pyを使ってインストールし、site-packagesに入れておけば問題は解決します。あなたが作るすべてを一つのパッケージに詰める必要はありません。それをバラバラにする。

1
user3181121

私は、スクリプトの親ディレクトリからパッケージをインポートするために、以下の方法がうまくいくことを見つけました。この例では、env.pyパッケージからapp.db内の関数をインポートします。

.
└── my_application
    └── alembic
        └── env.py
    └── app
        ├── __init__.py
        └── db
import os
import sys
currentdir = os.path.dirname(os.path.realpath(__file__))
parentdir = os.path.dirname(currentdir)
sys.path.append(parentdir)
0
Yu N.

Linuxシステムでは、 "life"フォルダからnib.pyファイルへのソフトリンクを作成できます。それから、インポートすることができます:

import nib
0