Pythonの相対パス


245

コードベースのいくつかのテンプレートファイルを現在のディレクトリにコピーする作業用の簡単なヘルパースクリプトを作成しています。ただし、テンプレートが保存されているディレクトリへの絶対パスはありません。スクリプトからの相対パスがありますが、スクリプトを呼び出すと、現在の作業ディレクトリからの相対パスとして処理されます。この相対URLが代わりにスクリプトの場所からであることを指定する方法はありますか?


回答:


324

スクリプトを含むファイルで、次のようなことを行います。

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

これにより、探しているファイルへの絶対パスが得られます。setuptoolsを使用している場合は、代わりにそのパッケージリソースAPIを使用する必要があることに注意してください。

更新:コードサンプルを貼り付けることができるように、ここでコメントに返信しています。:-)

__file__常に利用できるとは限らない(たとえば、ファイルをインポートするのではなく、直接実行する場合)と思いますか?

__main__ファイルの直接実行について言及するときは、スクリプトを意味していると思います。もしそうなら、それは私のシステム(OS X 10.5.7のPython 2.5.1)には当てはまらないようです。

#foo.py
import os
print os.getcwd()
print __file__

#in the interactive interpreter
>>> import foo
/Users/jason
foo.py

#and finally, at the shell:
~ % python foo.py
/Users/jason
foo.py

しかし、私はいくつかの癖があることを知っています __file__ Cの拡張機能。たとえば、Macでこれを行うことができます。

>>> import collections #note that collections is a C extension in Python 2.5
>>> collections.__file__
'/System/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5/lib-
dynload/collections.so'

ただし、これにより、Windowsマシンで例外が発生します。


1
ファイルが常に利用可能であるとは限らないと思いますか(たとえば、ファイルをインポートするのではなく直接実行する場合)?
スティーブンエドモンズ

@Stephen Edmondsインポートではなく、自分が実行するファイルを使用しています。
baudtack 2009年

22
あなたは移植性のためにどこでもos.path.join使用する必要があります注意:filename = os.path.join(dir, 'relative', 'path', 'to', 'file', 'you' , 'want')
フォード

22
os.path.dirname(__file__)空の文字列を与えることができます。os.path.dirname(os.path.abspath(__file__))代わりに使用してください
Dmitry Trofimov

14
些細なことですが、dirは組み込みなので、変数名として使用しないでください。
デビッド

63

あなたは必要ですos.path.realpath(以下のサンプルは親ディレクトリをパスに追加します)

import sys,os
sys.path.append(os.path.realpath('..'))

2
os.path.dirname(__file__)空の文字列をくれました。これは完全に機能しました。
Darragh Enright 2014

3
これは、スクリプトの場所ではなく、スクリプトが実行されるディレクトリの親を与えるようです。
コクリコ2017

10
os.path.realpath('..')現在の作業ディレクトリの親ディレクトリを提供します。それは通常だではない何をしたいです。
Martijn Pieters

1
@DarraghEnright:これは、Python-script-to-exeパッケージ環境でのみ発生します。これは、現在の作業ディレクトリに依存することが代替手段となる、まれな例外の1つです。
Martijn Pieters

52

受け入れられた答えで述べたように

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, '/relative/path/to/file/you/want')

追加したいだけです

後者の文字列はバックスラッシュで始めることはできません。文字列にバックスラッシュを含めることはできません。

それは次のようなものでなければなりません

import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, 'relative','path','to','file','you','want')

受け入れられた回答は、場合によっては誤解を招く可能性があります。詳細については、このリンクを参照してください


4
はい、使用os.path.joinするとOS固有の区切り文字で結合されるため、使用することをお勧めします。
Farshid T 2016

'/relative/path...'は相対パスではありません。それは意図的ですか?
steveire 2018

で適切な相対パスを使用するように上部の回答が編集されているため、この回答は古くなっていos.path.join()ます。残っているのは、パスセパレーターをハードコーディングするよりも、パス要素ごとに個別の文字列を使用する設定です。
Martijn Pieters

@MartijnPietersはい、トップの回答はこれに部分的に一致するように編集されていますが、個別の文字列は好みではありません-このように文字列を分離すると、OSに依存しなくなります。
jshrimp29

26

それは今2018年であり、Pythonはすでに__future__ずっと前に進化しています。それでは、どのよう驚くほどの使用に関するpathlibタスクの代わりに苦しんを達成するためにはPython 3.4で来てosos.pathglobshutilなど、

したがって、ここには3つのパスがあります(重複している可能性があります)。

  • mod_pathシンプルなヘルパースクリプトのパス
  • src_path:コピー待ちのテンプレートファイルがいくつか含まれいます。
  • cwd現在のディレクトリ、これらのテンプレートファイルの宛先。

問題は次のとおりです。私たちが持っていないのフルパスをsrc_path、唯一知っていることの相対パスにしますmod_path

今、驚くべきことでこれを解決しましょうpathlib

# Hope you don't be imprisoned by legacy Python code :)
from pathlib import Path

# `cwd`: current directory is straightforward
cwd = Path.cwd()

# `mod_path`: According to the accepted answer and combine with future power
# if we are in the `helper_script.py`
mod_path = Path(__file__).parent
# OR if we are `import helper_script`
mod_path = Path(helper_script.__file__).parent

# `src_path`: with the future power, it's just so straightforward
relative_path_1 = 'same/parent/with/helper/script/'
relative_path_2 = '../../or/any/level/up/'
src_path_1 = (mod_path / relative_path_1).resolve()
src_path_2 = (mod_path / relative_path_2).resolve()

将来的には、それはとても簡単です。:D


さらに、これらのテンプレートファイルを選択してチェックし、コピー/移動できますpathlib

if src_path != cwd:
    # When we have different types of files in the `src_path`
    for template_path in src_path.glob('*.ini'):
        fname = template_path.name
        target = cwd / fname
        if not target.exists():
            # This is the COPY action
            with target.open(mode='wb') as fd:
                fd.write(template_path.read_bytes())
            # If we want MOVE action, we could use:
            # template_path.replace(target)

14

私のコードを考えてみましょう:

import os


def readFile(filename):
    filehandle = open(filename)
    print filehandle.read()
    filehandle.close()



fileDir = os.path.dirname(os.path.realpath('__file__'))
print fileDir

#For accessing the file in the same folder
filename = "same.txt"
readFile(filename)

#For accessing the file in a folder contained in the current folder
filename = os.path.join(fileDir, 'Folder1.1/same.txt')
readFile(filename)

#For accessing the file in the parent folder of the current folder
filename = os.path.join(fileDir, '../same.txt')
readFile(filename)

#For accessing the file inside a sibling folder.
filename = os.path.join(fileDir, '../Folder2/same.txt')
filename = os.path.abspath(os.path.realpath(filename))
print filename
readFile(filename)

これをWindowsで実行すると、次のエラーが表示されます。
lonstar

11

sys.pathを参照してください プログラムの起動時に初期化されるため、このリストの最初の項目、path [0]は、Pythonインタープリターの呼び出しに使用されたスクリプトを含むディレクトリです。

このパスを、相対パス適用するルートフォルダとして使用します

>>> import sys
>>> import os.path
>>> sys.path[0]
'C:\\Python25\\Lib\\idlelib'
>>> os.path.relpath(sys.path[0], "path_to_libs") # if you have python 2.6
>>> os.path.join(sys.path[0], "path_to_libs")
'C:\\Python25\\Lib\\idlelib\\path_to_libs'

3
それは必ずしも本当ではありません。通常、sys.path [0]は空の文字列またはドットであり、現在のディレクトリへの相対パスです。現在のディレクトリが必要な場合は、os.getcwdを使用します。
Jason Baker、

元の投稿者は、現在の作業ディレクトリは相対パスのベースとなる場所が間違っているとコメントしています。あなたはsys.path [0]が常に有効であるとは限らないと言っているのは正しいです。
トムレイ、

いいえ、sys.path[0]常に親ディレクトリに設定されるわけではありません。Pythonコードを用いて呼び出すことができる-cか、-mまたはポイントをれる埋め込みインタプリタを介してsys.path[0]全く異なるものに設定されています。
Martijn Pieters

6

使用する代わりに

import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

受け入れられた回答のように、使用する方がより堅牢です:

import inspect
import os
dirname = os.path.dirname(os.path.abspath(inspect.stack()[0][1]))
filename = os.path.join(dirname, 'relative/path/to/file/you/want')

__file__を使用すると、モジュールのロード元のファイルが返されます。ファイルからロードされた場合、スクリプトを含むファイルが他の場所から呼び出された場合、返されるディレクトリは正しくありません。

これらの回答は詳細を提供します:https : //stackoverflow.com/a/31867043/5542253およびhttps://stackoverflow.com/a/50502/5542253


5
inspect.stack()呼び出すには高価な関数です。すべてのスタックフレームの情報を取得し、それを破棄して、上位のフレームのみを取得します。基本的にはinspect.getfile()、単にを返すモジュールオブジェクトを呼び出しますmodule.__file__。あなただけを使用するよりもはるかに優れてい__file__ます。
Martijn Pieters

4

こんにちは、まず最初に、関数os.path.abspath(path)os.path.relpath(path)を理解する必要があります

要するにos.path.abspath(path)絶対パスへの相対パスを作成します。また、指定されたパス自体が絶対パスの場合、関数は同じパスを返します。

同様にos.path.relpath(path)相対パスへの絶対パスを作成します。提供されたパス自体が相対パスの場合、関数は同じパスを返します。

以下の例では、上記の概念を正しく理解できます

Pythonスクリプトで処理する入力ファイルのリストを含むファイルinput_file_list.txtがあるとします。

D:\ conc \ input1.dic

D:\ conc \ input2.dic

D:\ Copyioconc \ input_file_list.txt

上記のフォルダー構造が表示される場合、input_file_list.txtCopyofconcフォルダーにあり、Pythonスクリプトで処理されるファイルはconcフォルダーにあります。

ただし、ファイルinput_file_list.txtの内容は次のとおりです。

.. \ conc \ input1.dic

.. \ conc \ input2.dic

そして、私のpythonスクリプトはD:ドライブにあります。

そして、で提供相対パスinput_file_list.txtファイルは、のパスを基準にしていinput_file_list.txtファイル。

したがって、Pythonスクリプトが現在の作業ディレクトリを実行する場合(パスを取得するにはos.getcwd()を使用)

私の相対パスはinput_file_list.txtからの相対パス、つまり"D:\ Copyofconc"なので、現在の作業ディレクトリを"D:\ Copyofconc"に変更する必要があります。

そのため、os.chdir( 'D:\ Copyofconc')を使用する必要があるため、現在の作業ディレクトリは「D:\ Copyofconc」になります。

次に、ファイルinput1.dicおよびinput2.dicを取得するために、「.. \ conc \ input1.dic」という行を読み取り、次のコマンドを使用します。

input1_path = os.path.abspath( '.. \ conc \ input1.dic')(相対パスを絶対パスに変更します。ここでは、現在の作業ディレクトリは「D:\ Copyofconc」なので、ファイル「。\ conc \ input1」です。 dic "は" D:\ Copyofconc "を基準にしてアクセスされます)

したがって、input1_pathは "D:\ conc \ input1.dic"になります


4

このコードは、メインスクリプトへの絶対パスを返します。

import os
def whereAmI():
    return os.path.dirname(os.path.realpath(__import__("__main__").__file__))

これはモジュールでも機能します。


再インポートする代わりに、を使用しますsys.modules['__main__'].__file__
Martijn Pieters

3

私のために働く代替:

this_dir = os.path.dirname(__file__) 
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))

0

私のために働いたのは使用していsys.path.insertます。次に、移動する必要があるディレクトリを指定しました。たとえば、1つ上のディレクトリに移動するだけで済みます。

import sys
sys.path.insert(0, '../')

1
これは、現在の作業ディレクトリに依存しており、実際のディレクトリとは根本的に異なる可能性があります。
Martijn Pieters

-2

これが古いバージョンの一部に当てはまるかどうかはわかりませんが、Python 3.3はネイティブ相対パスをサポートしていると思います。

たとえば、次のコードは、pythonスクリプトと同じフォルダーにテキストファイルを作成する必要があります。

open("text_file_name.txt", "w+t")

(相対パスの場合は、先頭にスラッシュやバックスラッシュを入れないでください)


正しいので、これはOPが要求するものではないCWDから機能します。スクリプトの場所から作業したい。
Samy Bencherif 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.