web-dev-qa-db-ja.com

Pythonの相対パス

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

184
baudtack

スクリプトを含むファイルでは、次のようにします。

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

これにより、探しているファイルへの絶対パスがわかります。 setuptoolsを使用している場合は、おそらく代わりに package resources API を使用してください。

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

私は__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

しかし、私は、Cの拡張機能に関して__file__に関するいくつかの奇妙な点があることを知っています。たとえば、私の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マシンでは例外が発生します。

247
Jason Baker

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

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

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

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')

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

46
Ahmed

私のコードを見てください。

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)
13
Fahad Haleem

を参照してください。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'
10
Tom Leys

2018年になり、Pythonは既に__future__に進化しています。では、pathlibos.pathosglobなどに苦労するのではなく、タスクを達成するためにPython 3.4に付属の驚くべき shutil を使用してみてください。

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

  • mod_pathsimple helper scriptのパス
  • src_path:これには、コピーを待機しているいくつかのテンプレートファイルが含まれています
  • cwdcurrent directory、これらのテンプレートファイルの宛先。

そして問題は:持っていない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)
9
YaOzI

使用する代わりに

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/554225 そして https://stackoverflow.com/a/50502/554225

5
smiley

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

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

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

4
BookOwl

こんにちは最初にあなたは関数を理解する必要があります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.dicinput2.dicというファイルを取得するために、 "..\conc\input1.dic"という行を読み、次にコマンドを使用します。

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

so input1_pathは "D:\ conc\input1.dic"になります

3

私のために働く代替手段:

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

私にとってうまくいったのはsys.path.insertを使うことです。それから私は私が行く必要があるディレクトリを指定しました。たとえば、1つ上のディレクトリに移動する必要がありました。

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