344

Python で現在のスクリプト ディレクトリを特定する最善の方法を知りたいです。

私は、Python コードを呼び出す方法がたくさんあるため、適切な解決策を見つけるのが難しいことを発見しました。

ここにいくつかの問題があります:

  • __file__スクリプトが で実行される場合、 は定義されませんexecexecfile
  • __module__モジュールでのみ定義されます

使用例:

  • ./myfile.py
  • python myfile.py
  • ./somedir/myfile.py
  • python somedir/myfile.py
  • execfile('myfile.py')(別のスクリプトから、別のディレクトリに配置でき、別の現在のディレクトリを持つことができます。

完璧な解決策がないことはわかっていますが、ほとんどの場合を解決する最善の方法を探しています。

最もよく使われる方法は ですos.path.dirname(os.path.abspath(__file__))が、別のスクリプトからexec().

警告

現在のディレクトリを使用するソリューションは失敗します。これは、スクリプトが呼び出される方法に基づいて異なるか、実行中のスクリプト内で変更される可能性があります。

4

16 に答える 16

291
os.path.dirname(os.path.abspath(__file__))

本当にあなたが得ようとしている最高のものです。

exec/を使用してスクリプトを実行するのは珍しいことexecfileです。通常は、モジュール インフラストラクチャを使用してスクリプトをロードする必要があります。これらのメソッドを使用する必要がある場合は、スクリプトに渡す を設定__file__して、globalsそのファイル名を読み取れるようにすることをお勧めします。

実行されたコードでファイル名を取得する方法は他にありません。お気づきのように、CWD はまったく別の場所にある可能性があります。

于 2010-09-15T15:01:21.187 に答える
147

スクリプトが 経由で呼び出されるケースを本当にカバーしたい場合はexecfile(...)、モジュールを使用しinspectてファイル名 (パスを含む) を推測できます。私が知る限り、これはあなたがリストしたすべてのケースで機能します:

filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))
于 2011-06-02T02:49:46.077 に答える
6

だろう

import os
cwd = os.getcwd()

あなたがしたいことをしますか?「現在のスクリプト ディレクトリ」とは正確には何を意味するのかわかりません。あなたが与えたユースケースに対して期待される出力は何ですか?

于 2010-09-15T14:59:29.167 に答える
5

を使用os.path.dirname(os.path.abspath(__file__))する場合に本当に必要かどうかを慎重に検討してexecください。スクリプトをモジュールとして使用できない場合は、問題のある設計の兆候である可能性があります。

Zen of Python #8を念頭に置いてください。それが機能しなければならないユースケースに適切な議論があると思われる場合はexec、問題の背景に関する詳細をお知らせください。

于 2011-06-04T10:53:03.680 に答える
4

注:この回答はパッケージになりました

https://github.com/heetbeet/locate

$ pip install locate

$ python
>>> from locate import this_dir
>>> print(this_dir())
C:/Users/simon

.pyスクリプトおよびインタラクティブな使用の場合:

私は頻繁にスクリプトのディレクトリを使用しますが (一緒に保存されているファイルにアクセスするため)、これらのスクリプトをデバッグ目的で対話型シェルで実行することもよくあります。私は次のように定義__dirpath__します。

  • ファイルを実行またはインポートするとき.pyの、ファイルのベース ディレクトリ。これは常に正しいパスです。
  • ノートブックを実行している場合.ipyn、現在の作業ディレクトリ。Jupyter は作業ディレクトリを.ipynbベース ディレクトリとして設定するため、これは常に正しいパスです。
  • REPL で実行している場合、現在の作業ディレクトリ。うーん、コードがファイルから切り離されたときの実際の「正しいパス」は何ですか? むしろ、REPL を呼び出す前に「正しいパス」に変更する責任を負います。

Python 3.4 (およびそれ以降):

from pathlib import Path
__dirpath__ = Path(globals().get("__file__", "./_")).absolute().parent

Python 2 (およびそれ以降):

import os
__dirpath__ = os.path.dirname(os.path.abspath(globals().get("__file__", "./_")))

説明:

  • globals()すべてのグローバル変数を辞書として返します。
  • .get("__file__", "./_")"__file__"キーが に存在する場合はキーの値を返します。存在しglobals()ない場合は、指定されたデフォルト値を返します"./_"
  • コードの残りの部分は、絶対ファイルパスに展開__file__(または"./_") し、ファイルパスのベース ディレクトリを返します。
于 2020-10-25T10:43:24.000 に答える
3

まず..匿名コードを挿入する方法について話している場合、ここにいくつかのユースケースがありません..

code.compile_command()
code.interact()
imp.load_compiled()
imp.load_dynamic()
imp.load_module()
__builtin__.compile()
loading C compiled shared objects? example: _socket?)

しかし、本当の問題は、あなたの目標は何ですか - ある種のセキュリティを強制しようとしていますか? それとも、ロードされているものに興味がありますか。

securityに関心がある場合は、 exec/execfile を介してインポートされるファイル名は重要ではありません。以下を提供するrexecを使用する必要があります。

このモジュールには、r_eval()、r_execfile()、r_exec()、および r_import() メソッドをサポートする RExec クラスが含まれています。これらのメソッドは、標準 Python 関数 eval()、execfile()、および exec および import ステートメントの制限付きバージョンです。この制限された環境で実行されるコードは、安全と見なされるモジュールと関数にのみアクセスできます。必要に応じて RExec の追加または削除機能をサブクラス化できます。

ただし、これがより学術的な追求である場合は、もう少し深く掘り下げることができるいくつかの間抜けなアプローチを次に示します..

スクリプト例:

./深い.py

print ' >> level 1'
execfile('deeper.py')
print ' << level 1'

./deeper.py

print '\t >> level 2'
exec("import sys; sys.path.append('/tmp'); import deepest")
print '\t << level 2'

/tmp/deepest.py

print '\t\t >> level 3'
print '\t\t\t I can see the earths core.'
print '\t\t << level 3'

./codespy.py

import sys, os

def overseer(frame, event, arg):
    print "loaded(%s)" % os.path.abspath(frame.f_code.co_filename)

sys.settrace(overseer)
execfile("deep.py")
sys.exit(0)

出力

loaded(/Users/synthesizerpatel/deep.py)
>> level 1
loaded(/Users/synthesizerpatel/deeper.py)
    >> level 2
loaded(/Users/synthesizerpatel/<string>)
loaded(/tmp/deepest.py)
        >> level 3
            I can see the earths core.
        << level 3
    << level 2
<< level 1

もちろん、これはリソースを大量に消費する方法であり、すべてのコードをトレースすることになります.あまり効率的ではありません。でも、巣に深く入っても効き続けるので斬新なアプローチだと思います。「eval」をオーバーライドすることはできません。execfile() をオーバーライドできますが。

このアプローチは、「インポート」ではなく、exec/execfile のみを対象とすることに注意してください。より高いレベルの「モジュール」ロード フックについては、 sys.path_hooksを使用できる場合があります (PyMOTW の好意による書き込み)。

それが私の頭の上にあるすべてです。

于 2011-06-04T20:17:21.100 に答える
2

これは部分的な解決策ですが、これまでに公開されたすべての解決策よりも優れています。

import sys, os, os.path, inspect

#os.chdir("..")

if '__file__' not in locals():
    __file__ = inspect.getframeinfo(inspect.currentframe())[0]

print os.path.dirname(os.path.abspath(__file__))

現在、これはすべての呼び出しで機能しますが、誰かがchdir()現在のディレクトリを変更するために使用すると、これも失敗します。

ノート:

  • sys.argv[0]-c動作しません。スクリプトを実行すると返されますpython -c "execfile('path-tester.py')"
  • https://gist.github.com/1385555で完全なテストを公開しました。改善を歓迎します。
于 2011-11-22T12:26:08.367 に答える
1

ほとんどの場合、これでうまくいくはずです:

import os,sys
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))
于 2015-06-14T16:52:11.133 に答える
1

利用可能な場合__file__:

# -- script1.py --
import os
file_path = os.path.abspath(__file__)
print(os.path.dirname(file_path))

インタープリターからコマンドを実行したり、スクリプトを実行している場所のパスを取得したりしたい場合:

# -- script2.py --
import os
print(os.path.abspath(''))

これはインタプリタから機能します。ただし、スクリプトで実行する (またはインポートする) と、印刷されたスクリプトを含むディレクトリのパスではなく、スクリプトを実行した場所のパスが表示されます。

例:

ディレクトリ構造が

test_dir (in the home dir)
├── main.py
└── test_subdir
    ├── script1.py
    └── script2.py

# -- main.py --
import script1.py
import script2.py

出力は次のとおりです。

~/test_dir/test_subdir
~/test_dir
于 2020-12-04T11:08:22.670 に答える