Pythonで現在実行されているファイルのパスを取得するにはどうすればよいですか?


193

これは初心者の質問のように思えるかもしれませんが、そうではありません。一部の一般的なアプローチは、すべての場合に機能するわけではありません。

sys.argv [0]

これは、を使用することを意味しpath = os.path.abspath(os.path.dirname(sys.argv[0]))ますが、別のディレクトリの別のPythonスクリプトから実行している場合は機能しません。これは実際に発生する可能性があります。

__ファイル__

これはを使用することを意味しますがpath = os.path.abspath(os.path.dirname(__file__))、これは機能しないことがわかりました。

  • py2exe__file__属性はありませんが、回避策があります
  • IDLEから実行すると属性execute()がない__file__
  • OS X 10.6の入手先 NameError: global name '__file__' is not defined

不完全な回答のある関連質問:

上記のすべてのユースケースで機能する一般的なソリューションを探しています。

更新

これはテストケースの結果です:

python a.pyの出力(Windowsの場合)

a.py: __file__= a.py
a.py: os.getcwd()= C:\zzz

b.py: sys.argv[0]= a.py
b.py: __file__= a.py
b.py: os.getcwd()= C:\zzz

a.py

#! /usr/bin/env python
import os, sys

print "a.py: sys.argv[0]=", sys.argv[0]
print "a.py: __file__=", __file__
print "a.py: os.getcwd()=", os.getcwd()
print

execfile("subdir/b.py")

subdir / b.py

#! /usr/bin/env python
import os, sys

print "b.py: sys.argv[0]=", sys.argv[0]
print "b.py: __file__=", __file__
print "b.py: os.getcwd()=", os.getcwd()
print

C:.
|   a.py
\---subdir
        b.py

回答:


80

実行中のメインスクリプトの場所を直接特定することはできません。結局のところ、スクリプトがファイルからまったく取得されない場合がありました。たとえば、対話型インタープリターや、メモリにのみ格納された動的に生成されたコードが原因である可能性があります。

ただし、モジュールは常にファイルから読み込まれるため、モジュールの場所を確実に特定できます。次のコードでモジュールを作成し、それをメインスクリプトと同じディレクトリに配置すると、メインスクリプトはモジュールをインポートし、それを使用してモジュール自体を見つけることができます。

some_path / module_locator.py:

def we_are_frozen():
    # All of the modules are built-in to the interpreter, e.g., by py2exe
    return hasattr(sys, "frozen")

def module_path():
    encoding = sys.getfilesystemencoding()
    if we_are_frozen():
        return os.path.dirname(unicode(sys.executable, encoding))
    return os.path.dirname(unicode(__file__, encoding))

some_path / main.py:

import module_locator
my_path = module_locator.module_path()

異なるディレクトリにいくつかのメインスクリプトがある場合、module_locatorの複数のコピーが必要になる場合があります。

もちろん、スクリプトと同じ場所にあるモジュールをインポートできない他のツールによってメインスクリプトが読み込まれている場合は、運が悪いです。そのような場合、あなたが探している情報は単にあなたのプログラムのどこにも存在しません。あなたの最善の策は、ツールの作者にバグを報告することです。


2
OS 10.6ではファイルNameError: global name '__file__' is not defined使用していますが、これはIDLEの内部にはありません。これ__file__はモジュール内でのみ定義されていると考えてください。
ソリン

1
@Sorin Sbarnea:私はそれをどうやって回避するかで私の答えを更新しました。
Daniel Stutzbach、2010

2
ありがとう、しかし実際には、行方不明の問題__file__はUnicodeとは何の関係もありませんでした。なぜ__file__が定義されていないのかわかりませんが、これがすべてのケースで機能する一般的なソリューションを探しています。
ソリン

1
申し訳ありませんが、これはすべての場合で可能ではありません。たとえば、wscriptファイル(python)内からwaf.googlecode.comでこれを実行しようとします。これらのファイルは実行されますが、モジュールではなく、モジュールにすることはできません(ソースツリーの任意のサブディレクトリにすることができます)。
ソリン

1
some_path/module_locator.py代わりにその場所を教えてくれませんか?
Casebash 2013年

68

まず、あなたからインポートする必要があるinspectos

from inspect import getsourcefile
from os.path import abspath

次に、ソースファイルを見つけたいところはどこでも

abspath(getsourcefile(lambda:0))

ベストアンサー。ありがとうございました。
デヴァンウィリアムズ

4
すばらしい答えです。ありがとう。また、これは最も短く、最も移植性のある(異なるos-esで実行される)回答でもあり、NameError: global name '__file__' is not defined(別の解決策が原因である)などの問題は発生しません。
エドワード

同様に短い別の可能性:lambda:_。それは私のために働きました-それが常にうまくいくかどうかはわかりません。lambda:0おそらく、計り知れないほど少量の速度で実行されます(または、それほど小さくないかもしれません...ロードの即時か0、グローバルのロードに対してより高速なものかもしれませ_ん)。
ArtOfWarfare 2017

私が試したほとんどすべての提案と同様に、これは、実行中のディレクトリファイル(デバッグ)ではなく、cwdを返すだけです。
ジェームズ

1
@James-このコードは実行中のファイルに挿入されます...実行してgetsourcefile(lambda:0)も意味がなくなりNone、対話型プロンプトで実行しようとすると戻ります(lambdaソースファイルにはがないためです)。インタラクティブ環境で別の関数またはオブジェクトが発生している場合、おそらくabspath(getsourcefile(thatFunctionOrObject))あなたにとってより役立つでしょうか?
ArtOfWarfare 2018

16

このソリューションは実行可能ファイルでも堅牢です

import inspect, os.path

filename = inspect.getframeinfo(inspect.currentframe()).filename
path     = os.path.dirname(os.path.abspath(filename))

2
これが正解です。これはでも機能しentry_point: console_scriptますが、他の回答はありません。
Polv 2018年

15

私は同様の問題に遭遇していましたが、これで問題が解決する可能性があります:

def module_path(local_function):
   ''' returns the module path without the use of __file__.  Requires a function defined
   locally in the module.
   from http://stackoverflow.com/questions/729583/getting-file-path-of-imported-module'''
   return os.path.abspath(inspect.getsourcefile(local_function))

通常のスクリプトとアイドル状態で動作します。私が言えることは、他の人のために試してみることです!

私の典型的な使用法:

from toolbox import module_path
def main():
   pass # Do stuff

global __modpath__
__modpath__ = module_path(main)

現在、__ file__ではなく__modpath__を使用しています。


2
PEP8コーディングスタイルガイドによると、名前の先頭と末尾に二重のアンダースコアを付けないで__modpath__ください。名前を変更する必要があります。また、おそらくglobalステートメントは必要ありません。そうでなければ+1!
martineau

4
実際には、ローカル関数をの呼び出しで定義できますmodule_path()。すなわちmodule_path(lambda _: None)、それはしているスクリプトの他のコンテンツに依存しない。
マーティ

@martineau:私はあなたの提案を取り入れlambda _: None、過去2年間近くそれを使用しましたが、たった今、私はそれをにまで凝縮できることを発見しましたlambda:0。引数_をまったく指定せずに、引数を無視して、指定した形式を提案した特別な理由はありますか?None単なるスペースではなく、スペースを前に付けることについて何か優れた点はあり0ますか?どちらも同じように不可解ですが、1つは8文字で、もう1つは14文字です。
ArtOfWarfare 2015年

@ArtOfWarfare:2つの違いは、lambda _:引数を1つ取る関数であり、引数をlambda:取らない関数です。関数が呼び出されることはないので、問題ではありません。同様に、どの戻り値が使用されるかは問題ではありません。None何をすべきか、決して呼ばれることのない機能の方が優れていたと当時は思われていたので、私が選んだと思います。その前のスペースはオプションであり、読みやすさを向上させるためだけにあります(常にPEP8をフォローしようとすると習慣が形成されます)。
martineau 2015年

@martineau:それは明らかに悪用ですlambdaが、意図されていない何かにそれを使用します。あなたがPEP8に従うなら、私はそれのための正しい内容はそうpassではないだろうと思いますNoneが、ステートメントをに置くことは有効ではないlambdaので、値を持つ何かを入れなければなりません。そこには、中に入れることができ、いくつかの有効な2文字のものですが、私はあなたが置くことができる唯一の有効な単一文字のものは0-9だと思います(または外に割り当てられた単一文字の変数名lambda。)私は理解0最高は0-の虚無を示し、 9。
ArtOfWarfare 2015年

6

簡単に言うと、必要な情報を取得するための保証された方法はありませんが、実際にはほとんど常に機能するヒューリスティックがあります。で、あなたは見えるかもしれませんどのように私はCで実行可能ファイルの場所を見つけるのですか?。Cの観点から問題を説明しますが、提案されたソリューションはPythonに簡単に転記できます。


私は今、メタに関する議論を始めましたのでこんにちは、私のフラグが拒否された:meta.stackoverflow.com/questions/277272/...は
ArtOfWarfare

ただし、このページにはすでに簡単な実用的な回答があります。私のソリューションはうまく機能します:stackoverflow.com/a/33531619/3787376
エドワード

5

私の回答が信頼できない変数を使用しない理由を含む関連情報については、質問「親フォルダーからのモジュールのインポート」への私の回答を参照してください__file__。この単純な解決策は、モジュールとして異なるオペレーティングシステムとの相互互換性がなければならないosinspectのPythonの一部として来ます。

まず、inspectモジュールとosモジュールの一部をインポートする必要があります。

from inspect import getsourcefile
from os.path import abspath

次に、Pythonコードで必要な他の場所で次の行を使用します。

abspath(getsourcefile(lambda:0))

使い方:

組み込みモジュールos(以下の説明)から、abspathツールがインポートされます。

Mac、NT、PosixのOSルーチンは、使用しているシステムによって異なります。

次にgetsourcefile(以下の説明)が組み込みモジュールからインポートされますinspect

ライブPythonオブジェクトから有用な情報を取得します。

  • abspath(path) ファイルパスの絶対/完全バージョンを返します
  • getsourcefile(lambda:0)どういうわけかラムダ関数オブジェクトの内部ソースファイルを取得するため'<pyshell#nn>'、Pythonシェルに戻るか、現在実行されているPythonコードのファイルパスを返します。

abspathの結果でを使用getsourcefile(lambda:0)すると、生成されたファイルパスがPythonファイルの完全なファイルパスであることを確認できます。
この説明されたソリューションはもともと、Pythonで現在実行されているファイルのパスを取得するにどうすればよいですか?の回答のコードに基づいていました


ええ、私は同じ解決策を思いついただけです...それは確実に実行できないと言うだけの答えよりもはるかに優れています...質問が私が何であると思うかを尋ねていないのでない限り...
Grady Player

5

あなたは単に呼び出しました:

path = os.path.abspath(os.path.dirname(sys.argv[0]))

の代わりに:

path = os.path.dirname(os.path.abspath(sys.argv[0]))

abspath()sys.argv[0](コードが入っているファイル名)の絶対パスを提供しdirname()、ファイル名なしのディレクトリパスを返します。


3

これは、クロスプラットフォームの方法でトリックを実行するはずです(インタープリターなどを使用していない限り)。

import os, sys
non_symbolic=os.path.realpath(sys.argv[0])
program_filepath=os.path.join(sys.path[0], os.path.basename(non_symbolic))

sys.path[0]呼び出し元のスクリプトがあるディレクトリです(そのスクリプトが使用するモジュールを最初に探す場所)。ファイル自体の名前を最後から外すことができますsys.argv[0](これはで行ったものですos.path.basename)。os.path.joinクロスプラットフォームの方法でそれらをくっつけるだけです。os.path.realpathスクリプト自体とは異なる名前のシンボリックリンクを取得しても、スクリプトの実際の名前が取得されることを確認するだけです。

Macを持っていません。そのため、これについてはまだテストしていません。正常に機能するかどうか、お知らせください。私はこれをLinux(Xubuntu)とPython 3.4でテストしました。この問題の多くの解決策はMacでは機能しないことに注意してください(__file__Macには存在しないと聞いたため)。

スクリプトがシンボリックリンクの場合は、リンク先のファイルのパスが表示されます(シンボリックリンクのパスは表示されません)。


2

モジュールPathから使用できpathlibます:

from pathlib import Path

# ...

Path(__file__)

call to parentを使用して、パスをさらに進むことができます。

Path(__file__).parent

この答えは、StackOverflowユーザーがよく言及している__file__ように、信頼できない可能性のある変数を使用します(常に完全なファイルパスではない、すべてのオペレーティングシステムで機能しないなど)。回答を含めないように変更すると、問題が減り、相互互換性が高まります。詳細については、stackoverflow.com/ a/ 33532002/3787376を参照してください。
エドワード

@ mrroot5 OK、コメントを削除してください。
ガブリエルコーエン

1

コードがファイルからのものである場合、完全な名前を取得できます

sys._getframe().f_code.co_filename

次のように関数名を取得することもできます f_code.co_name


0

以下を追加するだけです。

from sys import *
path_to_current_file = sys.argv[0]
print(path_to_current_file)

または:

from sys import *
print(sys.argv[0])

0

私の解決策は:

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

-1
import os
current_file_path=os.path.dirname(os.path.realpath('__file__'))

これは意味がありません。まず、'__file__'文字列__file__であってはなりません。次に、そうした場合、これは、このコード行が含まれているファイルに対してのみ機能し、実行されるファイルに対しては機能しませんか?
Andreas Storvik Strauman、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.