モジュールが変更されたかどうかを検出したい。さて、inotify の使用は簡単です。通知を取得したいディレクトリを知る必要があるだけです。
Pythonでモジュールのパスを取得するにはどうすればよいですか?
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__)
モジュールのディレクトリを取得します。
inspect
Pythonにはモジュールがあります。
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__
(以下に再度示されています)。__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
お役に立てれば。この警告により、提示された他のソリューションをテストする際に、多くの時間と混乱が生じました。
この質問についても、いくつかのバリエーションに取り組んでみます。
(これらの質問のいくつかは 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' が返されます。別のディレクトリから呼び出して (たとえば、ディレクトリ bar に 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 -> file_import_testing.py
@SummerBreeze は、inspectモジュールの使用について言及しています。
これは、インポートされたモジュールに対してうまく機能するようで、非常に簡潔です。
import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)
素直に絶対パスを返します。現在実行中のスクリプトのパスを見つけるには:
inspect.getfile(inspect.currentframe())
(ありがとう @jbochi)
inspect.getabsfile(inspect.currentframe())
現在実行中のスクリプトの絶対パスを提供します (@Sadman_Sakib に感謝)。
誰もこれについて話していない理由はわかりませんが、私にとって最も簡単な解決策は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]. スペックが返ってきました。それがたまたま None に設定されている場合、ValueError が発生します。モジュールが sys.modules にない場合、sys.meta_path は、ファインダーに与えられた「パス」の値で適切な仕様を検索します。仕様が見つからない場合は、何も返されません。
名前がサブモジュール (ドットを含む) の場合、親モジュールが自動的にインポートされます。
name および package 引数は、importlib.import_module() と同じように機能します。つまり、相対的なモジュール名 (先行ドット付き) が機能します。
これは些細なことでした。
各モジュールには、__file__
現在の場所からの相対パスを示す変数があります。
したがって、モジュールに通知するためのディレクトリを取得するのは次のように簡単です。
os.path.dirname(__file__)
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)
import module
print module.__path__
パッケージは、もう 1 つの特別な属性
__path__
.__init__.py
これは、ファイル内のコードが実行される前に、パッケージを保持するディレクトリの名前を含むリストになるように初期化されます。この変数は変更できます。これを行うと、パッケージに含まれるモジュールとサブパッケージの今後の検索に影響します。この機能はあまり必要ではありませんが、パッケージ内のモジュール セットを拡張するために使用できます。
コマンドラインユーティリティに微調整できます。
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__))
モジュールをインポートすると、多くの情報にアクセスできます。チェックアウトしてくださいdir(a_module)
。パスに関しては、そのためのダンダーがあります: a_module.__path__
. モジュール自体を印刷することもできます。
>>> import a_module
>>> print(dir(a_module))
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
>>> print(a_module.__path__)
['/.../.../a_module']
>>> print(a_module)
<module 'a_module' from '/.../.../a_module/__init__.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
コツは通話のor '.'
後にありdirname()
ます。dir を として設定します。これは、現在のディレクトリ.
を意味し、パス関連の機能に対して有効なディレクトリです。
したがって、使用abspath()
する必要はありません。ただし、とにかく使用する場合は、トリックは必要ありません。abspath()
空のパスを受け入れ、それを現在のディレクトリとして適切に解釈します。
これを「プログラム」で動的に実行したい場合は、次のコードを試してください。
要点は、「ハードコード」するモジュールの正確な名前がわからない場合があるということです。リストから選択されているか、__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でエミュレートできると思います これはプログラム内にあるため、メソッドまたはモジュールに簡単に配置できます再利用。
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 による投稿に基づいて、コードを修正しました。
誰にとっても役立つ場合に備えて、簡単な 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 ~]#