質問
モジュールが変更されたかどうかを検出したい。これで、inotifyの使用は簡単で、通知を取得するディレクトリを知るだけで済みます。
Pythonでモジュールのパスを取得するにはどうすればよいですか
解決
import a_module
print(a_module.__file__)
実際には、少なくともMac OS Xでロードされた.pycファイルへのパスを提供します。だから私はできると思います:
import os
path = os.path.dirname(a_module.__file__)
次を試すこともできます:
path = os.path.abspath(a_module.__file__)
モジュールのディレクトリを取得します。
他のヒント
Pythonには inspect
モジュールがあります。
公式ドキュメント
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'
他の回答で述べたように、これを行う最良の方法は __ file __
を使用することです(以下に再度説明します)。ただし、重要な注意事項があります。モジュールを単独で実行している場合(つまり、 __ main __
として) __ file __
は存在しません。
たとえば、次の2つのファイルがあるとします(両方ともPYTHONPATHにあります):
#/path1/foo.py
import bar
print(bar.__file__)
and
#/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
これが役立つことを願っています。この警告は、提示された他のソリューションのテスト中に多くの時間と混乱をもたらしました。
この質問についてもいくつかのバリエーションに取り組みます:
- 呼び出されたスクリプトのパスを見つける
- 現在実行中のスクリプトのパスを見つける
- 呼び出されたスクリプトのディレクトリを見つける
(これらの質問のいくつかは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をディレクトリバーに置く)、次にいずれかを呼び出す
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.pyを指すシンボリックリンクfile_import_testing_linkを作成します。
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-&gt; file_import_testing.py
検査の使用
@SummerBreezeは、検査モジュールの使用について言及しています。
これはインポートされたモジュールに対してはうまく機能しているようで、非常に簡潔です:
import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)
従順に絶対パスを返します。ただし、現在実行中のスクリプトのパスを見つけるために、それを使用する方法がわかりませんでした。
これについて誰も話さない理由がわかりませんが、私にとって最も簡単な解決策は imp.find_module(&quot; modulename&quot;)(ドキュメントこちら):
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))
「検査」よりもこの方法の利点1つは、モジュールをインポートして動作させる必要がなく、入力に文字列を使用できることです。たとえば、別のスクリプトで呼び出されたモジュールをチェックするときに便利です。
編集:
python3では、 importlib
モジュールは以下を実行する必要があります。
importlib.util.find_spec
のドキュメント:
指定されたモジュールの仕様を返します。
最初に、sys.modulesがチェックされ、モジュールが既にインポートされているかどうかが確認されます。その場合、sys.modules [name]。 spec が返されます。それが起こる場合 Noneに設定すると、ValueErrorが発生します。モジュールが入っていない場合 sys.modules、次にsys.meta_pathで適切な仕様が検索されます ファインダーに与えられた「パス」の値。仕様ができなければ何も返されません 見つけられます。
サブモジュールの名前(ドットを含む)の場合、親モジュールは 自動的にインポートされます。
名前とパッケージの引数は、importlib.import_module()と同じように機能します。 つまり、相対モジュール名(先頭のドット付き)が機能します。
これは簡単でした。
各モジュールには、現在の場所からの相対パスを示す __ file __
変数があります。
したがって、モジュールのディレクトリを取得して通知するのは簡単です:
os.path.dirname(__file__)
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)
コマンドラインユーティリティ
コマンドラインユーティリティに微調整できます
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
だから私はpy2exeでこれをやろうとしてかなりの時間を費やしました 問題は、スクリプトがPythonスクリプトまたはpy2exe実行可能ファイルとして実行されているかどうかにかかわらず、スクリプトのベースフォルダーを取得することでした。また、現在のフォルダー、別のフォルダー、またはシステムのパスから(これが最も難しかった)実行されているかどうかを機能させるために。
最終的には、sys.frozenをpy2exeで実行するインジケーターとして使用して、このアプローチを使用しました。
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__))
import module
print module.__path__
パッケージは、もう1つの特別な属性
__ path __
をサポートします。これは 保持するディレクトリの名前を含むリストに初期化されます そのファイル内のコードが実行される前のパッケージの__ init __。py
この変数は変更できます。これを行うと、次の検索に影響します パッケージに含まれるモジュールとサブパッケージ。この機能はあまり必要ではありませんが、拡張機能に使用できます パッケージにあるモジュールのセット。
モジュールをインポートするだけです 次にその名前を押すと、完全なパスが表示されます
>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>
__ 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
トリックは、 dirname()
呼び出しの後のまたは '。'
にあります。 dirを。
に設定します。これは、現在のディレクトリを意味し、パス関連の関数の有効なディレクトリです。
したがって、 abspath()
を使用する必要はありません。しかし、とにかくそれを使用する場合、トリックは必要ありません: abspath()
は空白パスを受け入れ、現在のディレクトリとして適切に解釈します。
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()および< a href = "https://docs.python.org/3/library/os.path.html#os.path.realpath" rel = "nofollow noreferrer"> os.path.realpath()リターンパス現在の作業ディレクトリに基づいた結果。一般的に私たちが望むものではありません。 sys.argv リストの最初の要素は<リストをルートスクリプト自体で呼び出すか、モジュールで呼び出すかに関係なく、em>ルートスクリプトのパス(実行するスクリプト)。状況によっては便利かもしれません。 __file__ 変数には、呼び出されたモジュールのパスが含まれます。 。
次のコードは、スクリプトが置かれているのと同じディレクトリにファイル example.txt
を正しく作成します。
filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')
with open(filepath, 'w'):
pass
pythonパッケージのモジュール内から、packageと同じディレクトリにあるファイルを参照する必要がありました。例:
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による投稿に基づいて、コードを変更しました。
&quot; program&quot;でこれを動的に行う場合このコードを試してください:
私のポイントは、「ハードコード」するモジュールの正確な名前がわからない場合があることです。それ。
リストから選択されるか、__ 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'>
&quot; global&quot;を削除しようとしました。問題ですが、動作しない場合が見つかりました &quot; execfile()&quot;と思うPython 3でエミュレートできます これはプログラム内にあるため、メソッドまたはモジュールに簡単に配置して再利用できます。
スクリプトから絶対パスを知りたい場合は、パスを使用できますオブジェクト:
from pathlib import Path
print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())
現在のディレクトリを表す新しいパスオブジェクトを返します(os.getcwd()によって返されます)
パスを絶対パスにし、シンボリックリンクを解決します。新しいパスオブジェクトが返されます。
モジュールのいずれかからパッケージのルートパスを取得する場合、次のように動作します(Python 3.6でテスト済み):
from . import __path__ as ROOT_PATH
print(ROOT_PATH)
メインの __ init __。py
パスは、代わりに __ file __
を使用して参照することもできます。
これがお役に立てば幸いです!