コードベースのいくつかのテンプレートファイルを現在のディレクトリにコピーする作業用の簡単なヘルパースクリプトを作成しています。ただし、テンプレートが保存されているディレクトリへの絶対パスはありません。スクリプトからの相対パスがありますが、スクリプトを呼び出すと、現在の作業ディレクトリからの相対パスとして処理されます。この相対URLが代わりにスクリプトの場所からであることを指定する方法はありますか?
コードベースのいくつかのテンプレートファイルを現在のディレクトリにコピーする作業用の簡単なヘルパースクリプトを作成しています。ただし、テンプレートが保存されているディレクトリへの絶対パスはありません。スクリプトからの相対パスがありますが、スクリプトを呼び出すと、現在の作業ディレクトリからの相対パスとして処理されます。この相対URLが代わりにスクリプトの場所からであることを指定する方法はありますか?
回答:
スクリプトを含むファイルで、次のようなことを行います。
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マシンで例外が発生します。
filename = os.path.join(dir, 'relative', 'path', 'to', 'file', 'you' , 'want')
os.path.dirname(__file__)
空の文字列を与えることができます。os.path.dirname(os.path.abspath(__file__))
代わりに使用してください
あなたは必要ですos.path.realpath
(以下のサンプルは親ディレクトリをパスに追加します)
import sys,os
sys.path.append(os.path.realpath('..'))
os.path.dirname(__file__)
空の文字列をくれました。これは完全に機能しました。
os.path.realpath('..')
現在の作業ディレクトリの親ディレクトリを提供します。それは通常だではない何をしたいです。
受け入れられた答えで述べたように
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')
受け入れられた回答は、場合によっては誤解を招く可能性があります。詳細については、このリンクを参照してください
os.path.join
するとOS固有の区切り文字で結合されるため、使用することをお勧めします。
'/relative/path...'
は相対パスではありません。それは意図的ですか?
os.path.join()
ます。残っているのは、パスセパレーターをハードコーディングするよりも、パス要素ごとに個別の文字列を使用する設定です。
それは今2018年であり、Pythonはすでに__future__
ずっと前に進化しています。それでは、どのよう驚くほどの使用に関するpathlib
タスクの代わりに苦しんを達成するためにはPython 3.4で来てos
、os.path
、glob
、shutil
など、
したがって、ここには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)
私のコードを考えてみましょう:
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)
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'
sys.path[0]
常に親ディレクトリに設定されるわけではありません。Pythonコードを用いて呼び出すことができる-c
か、-m
またはポイントをれる埋め込みインタプリタを介してsys.path[0]
全く異なるものに設定されています。
使用する代わりに
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
inspect.stack()
呼び出すには高価な関数です。すべてのスタックフレームの情報を取得し、それを破棄して、上位のフレームのみを取得します。基本的にはinspect.getfile()
、単にを返すモジュールオブジェクトを呼び出しますmodule.__file__
。あなただけを使用するよりもはるかに優れてい__file__
ます。
こんにちは、まず最初に、関数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.txtはCopyofconcフォルダーにあり、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"になります
このコードは、メインスクリプトへの絶対パスを返します。
import os
def whereAmI():
return os.path.dirname(os.path.realpath(__import__("__main__").__file__))
これはモジュールでも機能します。
sys.modules['__main__'].__file__
。
私のために働いたのは使用していsys.path.insert
ます。次に、移動する必要があるディレクトリを指定しました。たとえば、1つ上のディレクトリに移動するだけで済みます。
import sys
sys.path.insert(0, '../')
これが古いバージョンの一部に当てはまるかどうかはわかりませんが、Python 3.3はネイティブ相対パスをサポートしていると思います。
たとえば、次のコードは、pythonスクリプトと同じフォルダーにテキストファイルを作成する必要があります。
open("text_file_name.txt", "w+t")
(相対パスの場合は、先頭にスラッシュやバックスラッシュを入れないでください)