モジュールのパスを取得する方法は?


757

モジュールが変更されたかどうかを検出したい。これで、inotifyを使用するのは簡単です。通知を取得するディレクトリを知るだけで済みます。

Pythonでモジュールのパスを取得するにはどうすればよいですか?


1
modulefinderを確認してください:docs.python.org/library/modulefinder.html

9
このサイトをまだご覧になっている場合は、これに対する正しい答えを更新してください。提案されたソリューションよりもクリーンで、__file__が設定されていない場合でも機能します。
erikbwork 2013

3
@ erikb85:きれいなだけではありません。inspectベースのソリューションは、間違った名前をサイレントexecfile()__file__生成する場合にも機能します。
jfs


import pathlib, module; pathlib.Path(module.__file__).resolve().parentこれはプラットフォームに依存し
ません

回答:


907
import a_module
print(a_module.__file__)

実際には、少なくともMac OS Xでは、ロードされた.pycファイルへのパスが表示されます。したがって、次のようにできると思います。

import os
path = os.path.abspath(a_module.__file__)

あなたも試すことができます:

path = os.path.dirname(a_module.__file__)

モジュールのディレクトリを取得します。


54
これは、インポートするモジュールのパスを取得する方法に答えますが、現在のモジュール/スクリプトのパスは取得しません(実行しているスクリプトの場合__file__、完全なパスではなく、相対パスです)。私がいるファイルについては、同じディレクトリから別のモジュールをインポートし、ここに示すように実行する必要がありました。誰かがもっと便利な方法を知っていますか?
ベンブライアント

5
@hbdgaf組み込みのようなものはないことを確信していますself.__file__
Dan

26
@BenBryant @hbdgafは正常にos.path.dirname(__file__)動作し、モジュールのディレクトリのabsパスを返します。
ニコロ・

9
私はこれをやってみて、トレースバックを取得しました: AttributeError: 'module' object has no attribute '__file__'
Dorian Dore

5
@DorianDoreモジュールを少しいじって解決策を見つけましたがpath = module.__path__.__dict__["_path"][0]、移植性があるのか​​、それともPythonのバージョン間で違いがないのかわかりません。同じinspect答えが出て同じエラーが発生するこの回答とは異なり、それは私にとってはTypeError: <module 'module' (namespace)> is a built-in module
うまくいき

279

inspectPythonにはモジュールがあります。

公式ドキュメント

inspectモジュールは、モジュール、クラス、メソッド、関数、トレースバック、フレームオブジェクト、コードオブジェクトなどのライブオブジェクトに関する情報を取得するのに役立ついくつかの便利な関数を提供します。たとえば、クラスの内容を調べたり、メソッドのソースコードを取得したり、関数の引数リストを抽出してフォーマットしたり、詳細なトレースバックを表示するために必要なすべての情報を取得したりできます。

例:

>>> import os
>>> import inspect
>>> inspect.getfile(os)
'/usr/lib64/python2.7/os.pyc'
>>> inspect.getfile(inspect)
'/usr/lib64/python2.7/inspect.pyc'
>>> os.path.dirname(inspect.getfile(inspect))
'/usr/lib64/python2.7'

7
inspect現在のファイルの名前を取得するためにも使用できます。stackoverflow.com/a/50905/320036を
z0r

5
私はこの質問を何度もググっていましたが、これは私が今まで見た中で最も合理的な答えです!についての情報を更新してくださいinspect.currentframe()
erikbwork

このinspect.getfile()アプローチはモジュール_ioでは機能しませんが、モジュールでは機能しますio
smwikipedia 2014年

70

他の答えが言ったように、これを行うための最良の方法は__file__(以下で再度実証されています)です。ただし、重要な注意事項があり__file__ます__main__。つまり、モジュールを単独で(つまりとして)実行している場合は存在しません。

たとえば、2つのファイルがあるとします(どちらもPYTHONPATHにあります)。

#/path1/foo.py
import bar
print(bar.__file__)

そして

#/path2/bar.py
import os
print(os.getcwd())
print(__file__)

foo.pyを実行すると、出力が得られます。

/path1        # "import bar" causes the line "print(os.getcwd())" to run
/path2/bar.py # then "print(__file__)" runs
/path2/bar.py # then the import statement finishes and "print(bar.__file__)" runs

ただし、bar.pyを単独で実行しようとすると、次のようになります。

/path2                              # "print(os.getcwd())" still works fine
Traceback (most recent call last):  # but __file__ doesn't exist if bar.py is running as main
  File "/path2/bar.py", line 3, in <module>
    print(__file__)
NameError: name '__file__' is not defined 

お役に立てれば。この警告により、提示された他のソリューションをテストする間、多くの時間と混乱が生じました。


5
この場合、fileの代わりにsys.argv [0]を使用できます
ジモシー、2013

4
これはバージョン固有の警告ですか?2.6と2.7では、fileに依存することに成功しました。これは、name __ == '__ main 'のときにfileで機能します。私が見た唯一の失敗例は「python -c 'print file '」です。emacsのようなIDEが現在のバッファを実行するときに発生するファイルが「<stdin>」になることもあるということを付け加えます
Paul Du Bois

1
先頭と末尾の "__"文字は単語を太字にすることに注意してください。したがって、前のコメントを読むときはそのことを覚えておいてください。
Paul Du Bois

1
@PaulDuBoisバックチックで囲むことができます: ` __file__`が__file__
fncomp

1
どのように取得しNameErrorますか?@Paulデュボワ:私は、Python 2.3から3.4を試してみたと__file__私はPythonのファイルを実行しますが定義されます:python a.pypython -ma./a.py
jfs 14

43

この質問のいくつかのバリエーションにも取り組みます。

  1. 呼び出されたスクリプトのパスを見つける
  2. 現在実行中のスクリプトのパスを見つける
  3. 呼び出されたスクリプトのディレクトリを見つける

(これらの質問のいくつかはSOで尋ねられましたが、重複として閉じられ、ここにリダイレクトされました。)

使用上の注意 __file__

インポートしたモジュールの場合:

import something
something.__file__ 

モジュールの絶対パスを返します。ただし、次のスクリプトfoo.pyがあるとします。

#foo.py
print '__file__', __file__

'python foo.py'で呼び出すと、単に 'foo.py'が返されます。シバンを追加する場合:

#!/usr/bin/python 
#foo.py
print '__file__', __file__

./foo.pyを使用して呼び出すと、「./ foo.py」が返されます。別のディレクトリから呼び出し(たとえば、foo.pyをディレクトリbarに配置)、次のいずれかを呼び出します。

python bar/foo.py

またはシバンを追加してファイルを直接実行します:

bar/foo.py

'bar / foo.py'(相対パス)を返します。

ディレクトリを見つける

そこからディレクトリを取得するのはos.path.dirname(__file__)難しいかもしれません。少なくとも私のシステムでは、ファイルと同じディレクトリから呼び出すと空の文字列が返されます。例:

# foo.py
import os
print '__file__ is:', __file__
print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)

出力されます:

__file__ is: foo.py
os.path.dirname(__file__) is: 

つまり、空の文字列を返すため、現在のファイル(インポートされたモジュールのファイルではなく)に使用する場合は、信頼性が低いようです。これを回避するには、abspathの呼び出しでそれをラップできます。

# foo.py
import os
print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))

これは次のようなものを出力します:

os.path.abspath(__file__) is: /home/user/bar/foo.py
os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar

abspath()はシンボリックリンクを解決しないことに注意してください。これを行う場合は、代わりにrealpath()を使用してください。たとえば、シンボリックリンクfile_import_testing_linkがfile_import_testing.pyを指すようにし、次の内容を含めます。

import os
print 'abspath(__file__)',os.path.abspath(__file__)
print 'realpath(__file__)',os.path.realpath(__file__)

実行すると、次のような絶対パスが出力されます。

abspath(__file__) /home/user/file_test_link
realpath(__file__) /home/user/file_test.py

file_import_testing_link-> file_import_testing.py

検査を使用する

@SummerBreezeは、inspectモジュールの使用について言及しています。

インポートされたモジュールの場合、これはうまく機能するようで、非常に簡潔です:

import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)

絶対パスを素直に返します。しかし、現在実行中のスクリプトのパスを見つけるために、それを使用する方法がわかりませんでした。


1
inspect.getfile(os)は、コードのos .__ file__と同じです:def getfile(object): "" "オブジェクトが定義されたソースファイルまたはコンパイル済みファイルを計算します。" "" (object、 ' file '):return object .__ file__
idanzalz

4
を使用inspect.getfile(inspect.currentframe())して、現在実行中のスクリプトのパスを取得できます。
jbochi 2017年

33

誰もがこれについて話している理由がわかりませんが、私にとって最も簡単な解決策は、imp.find_module( "modulename")を使用することです(ドキュメントはこちら):

import imp
imp.find_module("os")

2番目の位置にパスを持つタプルを提供します。

(<open file '/usr/lib/python2.7/os.py', mode 'U' at 0x7f44528d7540>,
'/usr/lib/python2.7/os.py',
('.py', 'U', 1))

「検査」方法に対するこの方法の利点は、機能させるためにモジュールをインポートする必要がなく、文字列を入力で使用できることです。たとえば、別のスクリプトで呼び出されたモジュールをチェックするときに役立ちます。

編集

python3では、importlibモジュールは次のことを行う必要があります。

のドキュメントimportlib.util.find_spec

指定されたモジュールの仕様を返します。

最初に、sys.modulesがチェックされ、モジュールがすでにインポートされているかどうかが確認されます。その場合、sys.modules [name]。specが返されます。それがたまたまNoneに設定されると、ValueErrorが発生します。モジュールがsys.modulesにない場合、ファインダーに与えられた 'path'の値を使用して、sys.meta_pathで適切な仕様が検索されます。仕様が見つからなかった場合、Noneは返されません。

名前がサブモジュール用(ドットを含む)の場合、親モジュールが自動的にインポートされます。

名前とパッケージの引数はimportlib.import_module()と同じように機能します。言い換えると、(先頭にドットがある)相対モジュール名が機能します。


2
impはpython 2(現在のバージョン2.7.13)では廃止されていません。impは、Python 3で3.4以降廃止されています。代わりにimportlibがpython 3で使用されます。実際のインポートが失敗する場合でも機能するため(たとえば、32ビットエンジンの64ビットモジュールのため)、このソリューションが好きです
mdew

そして、64ビットのsqlite3のパスを見つけようとするとインポートは失敗し、本当にいいです。完璧です。
rahvin_t

2
importlib.machinery.PathFinder().find_module("os").get_filename()imp.find_module私がPython3 +で見つけたものの最も短い代替物。誰かがの使用を探している場合importlib.util.find_spec
トルクス

この方法は、実際のモジュールをインポートせずに機能します。これは、共有コンピューターからインポートされているモジュールのバージョンを確認するためにこれを使用しているので素晴らしいです。
ゴーダ

19

これは些細なことでした。

各モジュールには、__file__現在の場所からの相対パスを示す変数があります。

したがって、モジュールが通知するディレクトリを取得するのは次のように簡単です。

os.path.dirname(__file__)

14
ほぼ完全ではありませんが、ファイルは「現在の位置からの相対」ではありません。相対パスの場合(sys.pathに相対パスがある場合のみ)、モジュールが読み込まれたときの相対位置になります
Charles Duffy、

17
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)

1
__file__dir / test.pyなので、私のLinux python 2.6では機能しません。abspathはcwdを使用してパス名を完成させますが、これは望ましい結果ではありませんが、モジュールをインポートするとm.__file__、望ましい結果が得られます。
ベンブライアント

10
import module
print module.__path__

パッケージは、もう1つの特別な属性をサポートしています__path__。これは__init__.py、そのファイル内のコードが実行される前にパッケージを保持するディレクトリの名前を含むリストになるように初期化されます。この変数は変更できます。これにより、パッケージに含まれるモジュールおよびサブパッケージの今後の検索に影響します。

この機能は多くの場合必要ありませんが、パッケージにあるモジュールのセットを拡張するために使用できます。

ソース


9

コマンドラインユーティリティ

コマンドラインユーティリティに微調整できます。

python-which <package name>

ここに画像の説明を入力してください


作成する /usr/local/bin/python-which

#!/usr/bin/env python

import importlib
import os
import sys

args = sys.argv[1:]
if len(args) > 0:
    module = importlib.import_module(args[0])
    print os.path.dirname(module.__file__)

実行可能にする

sudo chmod +x /usr/local/bin/python-which

7

だから私はpy2exeでこれをやろうとするのにかなりの時間を費やしました問題は、それがpythonスクリプトとして実行されていても、py2exe実行可能ファイルとして実行されていても、スクリプトのベースフォルダーを取得することでした。また、現在のフォルダーから実行されていても、別のフォルダーから実行されていても、(これが最も困難でした)システムのパスから実行されていても機能します。

最終的に私はpy2exeで実行されていることの指標としてsys.frozenを使用して、このアプローチを使用しました。

import os,sys
if hasattr(sys,'frozen'): # only when running in py2exe this exists
    base = sys.prefix
else: # otherwise this is a regular python script
    base = os.path.dirname(os.path.realpath(__file__))

7

モジュールをインポートして、その名前を押すだけで、完全なパスを取得できます

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>

4

パッケージのいずれかのモジュールからパッケージのルートパスを取得する場合は、次のように動作します(Python 3.6でテスト済み)。

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

メイン__init__.pyパスは、__file__代わりにを使用して参照することもできます。

お役に立てれば!


3

__file__現在の相対ディレクトリが空白の場合(つまり、スクリプトと同じディレクトリからスクリプトとして実行する場合)を使用する場合の唯一の注意点は、簡単な解決策は次のとおりです。

import os.path
mydir = os.path.dirname(__file__) or '.'
full  = os.path.abspath(mydir)
print __file__, mydir, full

そしてその結果:

$ python teste.py 
teste.py . /home/user/work/teste

トリックはコールのor '.'後にありdirname()ます。dirをとして設定します.。これは、現在のディレクトリを意味しますし、パス関連機能の有効なディレクトリです。

したがって、abspath()実際に使用する必要はありません。しかし、とにかくそれを使用する場合、トリックは必要ありません。abspath()空白のパスを受け入れ、それを現在のディレクトリとして適切に解釈します。


順序を入れ替えて使用するのが良いos.path.dirname(os.path.abspath(__file__))でしょう。相対パスを気にする必要がないからです。バグの機会が1つ少なくなります。
szali

3

私は1つの一般的なシナリオ(Python 3)で貢献し、それにいくつかのアプローチを模索したいと思います。

組み込み関数open()は、最初の引数として相対パスまたは絶対パスを受け入れます。相対パスは現在の作業ディレクトリに対する相対パスとして扱われるため、ファイルへの絶対パスを渡すことをお勧めします。

簡単に言うと、次のコードでスクリプトファイルを実行した場合、そのファイルがスクリプトファイルと同じディレクトリに作成されるとは限りませexample.txt

with open('example.txt', 'w'):
    pass

このコードを修正するには、スクリプトへのパスを取得して絶対パスにする必要があります。パスが絶対パスであることを確認するには、os.path.realpath()関数を使用します。スクリプトへのパスを取得するには、さまざまなパスの結果を返すいくつかの一般的な関数があります。

  • os.getcwd()
  • os.path.realpath('example.txt')
  • sys.argv[0]
  • __file__

os.getcwd()os.path.realpath()の両方の関数は、現在の作業ディレクトリに基づいてパスの結果を返します。一般的に私たちが望むものではありません。sys.argvリストの最初の要素は、ルートスクリプト自体またはそのモジュールのいずれでリストを呼び出すかに関係なく、ルートスクリプト(実行するスクリプト)のパスです。場合によっては便利です。__file__の変数は、それが呼び出されたから、モジュールのパスが含まれています。


次のコードexample.txtは、スクリプトが配置されているのと同じディレクトリにファイルを正しく作成します。

filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')

with open(filepath, 'w'):
    pass

3

スクリプトから絶対パスを知りたい場合は、Pathオブジェクトを使用できます。

from pathlib import Path

print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())

cwd()メソッド

現在のディレクトリを表す新しいパスオブジェクトを返します(os.getcwd()によって返されます)

resolve()メソッド

パスを絶対パスにして、シンボリックリンクを解決します。新しいパスオブジェクトが返されます。


1

Pythonパッケージのモジュール内から、パッケージと同じディレクトリにあるファイルを参照する必要がありました。例

some_dir/
  maincli.py
  top_package/
    __init__.py
    level_one_a/
      __init__.py
      my_lib_a.py
      level_two/
        __init__.py
        hello_world.py
    level_one_b/
      __init__.py
      my_lib_b.py

したがって、上記では、top_packageとmaincli.pyが同じディレクトリにあることを認識して、my_lib_a.pyモジュールからmaincli.pyを呼び出す必要がありました。maincli.pyへのパスを取得する方法は次のとおりです。

import sys
import os
import imp


class ConfigurationException(Exception):
    pass


# inside of my_lib_a.py
def get_maincli_path():
    maincli_path = os.path.abspath(imp.find_module('maincli')[1])
    # top_package = __package__.split('.')[0]
    # mod = sys.modules.get(top_package)
    # modfile = mod.__file__
    # pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile)))
    # maincli_path = os.path.join(pkg_in_dir, 'maincli.py')

    if not os.path.exists(maincli_path):
        err_msg = 'This script expects that "maincli.py" be installed to the '\
        'same directory: "{0}"'.format(maincli_path)
        raise ConfigurationException(err_msg)

    return maincli_path

PlasmaBinturongによる投稿に基づいて、コードを変更しました。


1

これを「プログラム」で動的に実行したい場合
は、次のコードを試してください。つまり、「ハードコード」するモジュールの正確な名前がわからない場合があります。リストから選択するか、__ file__を使用するために現在実行されていない可能性があります。

(私は知っています、それはPython 3では動作しません)

global modpath
modname = 'os' #This can be any module name on the fly
#Create a file called "modname.py"
f=open("modname.py","w")
f.write("import "+modname+"\n")
f.write("modpath = "+modname+"\n")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:\Python27\lib\os.pyc'>

私は「グローバル」問題を取り除こうとしましたが、「execfile()」はPython 3でエミュレートできると思います。これはプログラム内にあるため、メソッドまたはモジュールに再利用。


0

pipを使用してインストールした場合、「pip show」は適切に機能します(「場所」)

$ピップショーdetectron2

Name: detectron2
Version: 0.1
Summary: Detectron2 is FAIR next-generation research platform for object detection and segmentation.
Home-page: https://github.com/facebookresearch/detectron2
Author: FAIR
Author-email: None
License: UNKNOWN
Location: /home/ubuntu/anaconda3/envs/pytorch_p36/lib/python3.6/site-packages
Requires: yacs, tabulate, tqdm, pydot, tensorboard, Pillow, termcolor, future, cloudpickle, matplotlib, fvcore

0

これは、誰にとっても便利なbashスクリプトです。pushdコードにアクセスできるように、環境変数を設定できるようにしたいだけです。

#!/bin/bash
module=${1:?"I need a module name"}

python << EOI
import $module
import os
print os.path.dirname($module.__file__)
EOI

シェルの例:

[root@sri-4625-0004 ~]# export LXML=$(get_python_path.sh lxml)
[root@sri-4625-0004 ~]# echo $LXML
/usr/lib64/python2.7/site-packages/lxml
[root@sri-4625-0004 ~]#
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.