[英]Relative paths in Python
我正在為工作構建一個簡單的幫助腳本,它將我們代碼庫中的幾個模板文件復制到當前目錄。 但是,我沒有存儲模板的目錄的絕對路徑。 我確實有來自腳本的相對路徑,但是當我調用腳本時,它會將其視為相對於當前工作目錄的路徑。 有沒有辦法指定這個相對 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
但是,我知道 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 機器上引發異常。
您需要os.path.realpath
(下面的示例將父目錄添加到您的路徑中)
import sys,os
sys.path.append(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')
在某些情況下,接受的答案可能會產生誤導,請參閱此鏈接了解詳細信息
現在是 2018 年,Python 早就進化到了__future__
。 那么如何使用 Python 3.4 pathlib
的驚人的pathlib
來完成任務,而不是在os
、 os.path
、 glob
、 shutil
等中掙扎。
所以我們這里有 3 條路徑(可能是重復的):
mod_path
: 這是簡單幫助腳本的路徑src_path
:其中包含幾個等待復制的模板文件。cwd
:當前目錄,這些模板文件的目的地。 而問題是:我們沒有的完整路徑src_path
,只知道它的的相對路徑mod_path
。
# 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'
而不是使用
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
嗨,首先你應該了解函數os.path.abspath(path)和os.path.relpath(path)
簡而言之os.path.abspath(path)使相對路徑到絕對路徑。 如果提供的路徑本身是絕對路徑,則該函數返回相同的路徑。
類似地, os.path.relpath(path)是相對路徑的絕對路徑。 如果提供的路徑本身是一個相對路徑,則該函數返回相同的路徑。
下面的例子可以讓你正確理解上述概念:
假設我有一個文件input_file_list.txt ,其中包含要由我的 python 腳本處理的輸入文件列表。
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__))
這甚至可以在模塊中工作。
對我有用的替代方法:
this_dir = os.path.dirname(__file__)
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))
>>> import os
>>> os.path.join('/home/user/tmp', 'subfolder')
'/home/user/tmp/subfolder'
>>> os.path.normpath('/home/user/tmp/../test/..')
'/home/user'
>>> os.path.relpath('/home/user/tmp', '/home/user')
'tmp'
>>> os.path.isabs('/home/user/tmp')
True
>>> os.path.isabs('/tmp')
True
>>> os.path.isabs('tmp')
False
>>> os.path.isabs('./../tmp')
False
>>> os.path.realpath('/home/user/tmp/../test/..') # follows symbolic links
'/home/user'
文檔中有詳細說明。 這些是linux路徑。 Windows 應該以類似的方式工作。
從其他人的建議和pathlib文檔中,一個簡單而清晰的解決方案如下(假設我們需要參考的文件: Test/data/users.csv
:
# This file location: Tests/src/long/module/subdir/some_script.py
from pathlib import Path
# back to Tests/
PROJECT_ROOT = Path(__file__).parents[4]
# then down to Test/data/users.csv
CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'
with CSV_USERS_PATH.open() as users:
print(users.read())
現在這對我來說看起來有點奇怪,因為如果你移動some_script.py
,我們項目根目錄的路徑可能會改變(我們需要修改parents[4]
)。 另一方面,我基於相同的想法找到了我更喜歡的解決方案。
假設我們有以下目錄結構:
Tests
├── data
│ └── users.csv
└── src
├── long
│ └── module
│ └── subdir
│ └── some_script.py
├── main.py
└── paths.py
paths.py
文件將負責存儲我們項目的根位置:
from pathlib import Path
PROJECT_ROOT = Path(__file__).parents[1]
所有腳本現在都可以使用paths.PROJECT_ROOT
來表示從項目根目錄開始的絕對路徑。 例如在src/long/module/subdir/some_script.py
我們可以有:
from paths import PROJECT_ROOT
CSV_USERS_PATH = PROJECT_ROOT / 'data' / 'users.csv'
def hello():
with CSV_USERS_PATH.open() as f:
print(f.read())
一切都按預期進行:
~/Tests/src/$ python main.py
/Users/cglacet/Tests/data/users.csv
hello, user
~/Tests/$ python src/main.py
/Users/cglacet/Tests/data/users.csv
hello, user
main.py
腳本就是:
from long.module.subdir import some_script
some_script.hello()
對我sys.path.insert
是使用sys.path.insert
。 然后我指定了我需要去的目錄。 例如,我只需要上一個目錄。
import sys
sys.path.insert(0, '../')
我認為與所有系統一起使用“ntpath”而不是“os.path”。 今天,它適用於 Windows、Linux 和 Mac OSX。
import ntpath
import os
dirname = ntpath.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
一個簡單的解決方案是
import os
os.chdir(os.path.dirname(__file__))
從C:\\Users\\xyz\\myFolder
到C:\\Users\\xyz\\testdata
:
import os
working_dir = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
# C:\Users\xyz\myFolder
print(working_dir)
updated_working_dir = os.path.join(os.path.realpath(working_dir + '/../'), 'testdata')
# C:\Users\xyz\testdata
print(updated_working_dir)
輸出
C:\Users\xyz\myFolder
C:\Users\xyz\testdata
示例,在 python 3.9.5 中測試
您當前的目錄:'c:\\project1\\code'
並且您想要訪問以下文件夾:“c:\\project1\\dataset\\train”。
然后您可以使用以下地址訪問該文件夾:'../dataset/train/'
我認為這可能對某人有用!
這是我的總結:
首先,定義名為relpath
的工具函數,它將當前文件的相對路徑轉換為 cwd 的相對路徑
import os
relpath = lambda p: os.path.normpath(os.path.join(os.path.dirname(__file__), p))
然后我們用它來包裝相對於當前文件的路徑
path1 = relpath('../src/main.py')
你也可以調用sys.path.append()
來導入相對於當前文件位置的文件
sys.path.append(relpath('..')) # so that you can import from upper dir
完整示例代碼: https : //gist.github.com/luochen1990/9b1ffa30f5c4a721dab5991e040e3eb1
假設當前存檔名為“Helper”,上層目錄名為“Workshop”,模板文件在\\Workshop\\Templates,那么Python中的相對路徑為“..\\Templates”。
這是一種將相對路徑添加到系統路徑集的簡單方法。 例如,對於目標目錄比工作目錄高一級(因此, '/../'
)的常見情況:
import os
import sys
workingDir = os.getcwd()
targetDir = os.path.join(os.path.relpath(workingDir + '/../'),'target_directory')
sys.path.insert(0,targetDir)
此解決方案經過測試:
Python 3.9.6 | conda-forge 打包| (默認,2021 年 7 月 11 日,03:37:25)[MSC v.1916 64 位 (AMD64)]
我不確定這是否適用於某些舊版本,但我相信 Python 3.3 具有本機相對路徑支持。
例如,以下代碼應在與 python 腳本相同的文件夾中創建一個文本文件:
open("text_file_name.txt", "w+t")
(請注意,如果是相對路徑,則開頭不應有正斜杠或反斜杠)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.