Ik ben een eenvoudig helperscript aan het bouwen voor werk dat een aantal sjabloonbestanden in onze codebasis naar de huidige map kopieert. Ik heb echter niet het absolute pad naar de map waar de sjablonen zijn opgeslagen. Ik heb wel een relatief pad van het script, maar wanneer ik het script aanroep, behandelt het dat als een pad ten opzichte van de huidige werkmap. Is er een manier om aan te geven dat deze relatieve url in plaats daarvan afkomstig is van de locatie van het script?
Antwoord 1, autoriteit 100%
In het bestand dat het script bevat, wil je zoiets als dit doen:
import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
Dit geeft je het absolute pad naar het bestand dat je zoekt. Houd er rekening mee dat als u setuptools gebruikt, u waarschijnlijk de pakketbronnen-APIin plaats daarvan.
UPDATE: ik reageer hier op een opmerking zodat ik een codevoorbeeld kan plakken. 🙂
Heb ik gelijk als ik denk dat
__file__
niet altijd beschikbaar is (bijvoorbeeld wanneer u het bestand rechtstreeks uitvoert in plaats van het te importeren)?
Ik neem aan dat je het __main__
-script bedoelt als je vermeldt dat het bestand rechtstreeks moet worden uitgevoerd. Als dat zo is, lijkt dat niet het geval te zijn op mijn systeem (python 2.5.1 op OS X 10.5.7):
#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
Ik weet echter wel dat er wat eigenaardigheden zijn met __file__
op C-extensies. Ik kan dit bijvoorbeeld op mijn Mac doen:
>>> 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'
Dit veroorzaakt echter een uitzondering op mijn Windows-computer.
Antwoord 2, autoriteit 17%
je hebt os.path.realpath
nodig (voorbeeld hieronder voegt de bovenliggende map toe aan je pad)
import sys,os
sys.path.append(os.path.realpath('..'))
Antwoord 3, autoriteit 15%
Zoals vermeld in het geaccepteerde antwoord
import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, '/relative/path/to/file/you/want')
Ik wil alleen dat toevoegen
de laatste string kan niet beginnen met de backslash , eigenlijk geen string
moet een backslash bevatten
Het zou zoiets moeten zijn als
import os
dir = os.path.dirname(__file__)
filename = os.path.join(dir, 'relative','path','to','file','you','want')
Het geaccepteerde antwoord kan in sommige gevallen misleidend zijn, raadpleeg dezelink voor details
Antwoord 4, autoriteit 12%
Het is nu 2018 en Python is al lang geleden geëvolueerd naar de __future__
. Dus hoe zit het met het gebruik van de geweldige pathlib
die bij Python wordt geleverd 3.4 om de taak te volbrengen in plaats van te worstelen met os
, os.path
, glob
, shutil
, enz.
We hebben hier dus 3 paden (mogelijk gedupliceerd):
mod_path
: dit is het pad van het eenvoudige helperscriptsrc_path
: die een paar sjabloonbestandenbevat die wachten om gekopieerd te worden.cwd
: huidige map, de bestemming van die sjabloonbestanden.
en het probleem is: we hebben niethet volledige pad van src_path
, we weten alleen het relatieve padnaar de mod_path
.
Laten we dit nu oplossen met de geweldige 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()
In de toekomst is het zo simpel. 😀
Bovendien kunnen we die sjabloonbestanden selecteren, controleren en kopiëren/verplaatsen met 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)
Antwoord 5, autoriteit 4%
Denk aan mijn code:
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)
Antwoord 6, autoriteit 3%
Zie sys.path
Zoals geïnitialiseerd bij het opstarten van het programma, is het eerste item van deze lijst, path[0], de map met het script dat werd gebruikt om de Python-interpreter aan te roepen.
Gebruik dit pad als de hoofdmap van waaruit u uw relatief pad
>>> 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'
Antwoord 7, autoriteit 2%
In plaats van
. te gebruiken
import os
dirname = os.path.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
zoals in het geaccepteerde antwoord, zou het robuuster zijn om te gebruiken:
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')
omdat het gebruik van __file__ het bestand teruggeeft waaruit de module is geladen, als het uit een bestand is geladen, dus als het bestand met het script van elders wordt aangeroepen, is de geretourneerde map niet correct.
Deze antwoorden geven meer details: https://stackoverflow.com/a/31867043/5542253en https://stackoverflow.com/a/50502/5542253
Antwoord 8
Hallo, allereerst moet u de functies os.path.abspath(path)en os.path.relpath(path)
begrijpen
Kortom os.path.abspath(path)maakt een relatief padnaar absoluut pad. En als het opgegeven pad zelf een absoluut pad is, retourneert de functie hetzelfde pad.
op dezelfde manier maakt os.path.relpath(path)een absoluut padnaar relatief pad. En als het opgegeven pad zelf een relatief pad is, retourneert de functie hetzelfde pad.
Het onderstaande voorbeeld kan u het bovenstaande concept goed laten begrijpen:
stel dat ik een bestand input_file_list.txtheb dat een lijst bevat van invoerbestanden die door mijn python-script moeten worden verwerkt.
D:\conc\input1.dic
D:\conc\input2.dic
D:\Copyioconc\input_file_list.txt
Als je bovenstaande mapstructuur ziet, is input_file_list.txtaanwezig in de map Copyofconcen zijn de bestanden die door het python-script moeten worden verwerkt aanwezig in concmap
Maar de inhoud van het bestand input_file_list.txtis zoals hieronder weergegeven:
..\conc\input1.dic
..\conc\input2.dic
En mijn python-script is aanwezig in de D:schijf.
En het relatieve pad in het bestand input_file_list.txtis relatief aan het pad van het bestand input_file_list.txt.
Dus wanneer python script de huidige werkmap zal uitvoeren (gebruik os.getcwd()om het pad te krijgen)
Aangezien mijn relatieve pad relatief is ten opzichte van input_file_list.txt, dat wil zeggen “D:\Copyofconc”, moet ik de huidige werkmap wijzigen in ” D:\Copyofconc”.
Dus ik moet os.chdir(‘D:\Copyofconc’)gebruiken, dus de huidige werkdirectory zal “D:\Copyofconc”zijn.
Om nu de bestanden input1.dicen input2.dicte krijgen, zal ik de regels “..\conc\input1.dic” lezen en dan het commando gebruiken
input1_path= os.path.abspath(‘..\conc\input1.dic’)(om relatief pad te veranderen in absoluut pad. Hier als huidige werkmap is “D:\Copyofconc” , zal het bestand “.\conc\input1.dic” worden benaderd relatief aan “D:\Copyofconc”)
dus input1_pathzal “D:\conc\input1.dic” zijn
Antwoord 9
Deze code retourneert het absolute pad naar het hoofdscript.
import os
def whereAmI():
return os.path.dirname(os.path.realpath(__import__("__main__").__file__))
Dit werkt zelfs in een module.
Antwoord 10
Een alternatief dat voor mij werkt:
this_dir = os.path.dirname(__file__)
filename = os.path.realpath("{0}/relative/file.path".format(this_dir))
Antwoord 11
samenvatting van de belangrijkste commando’s
>>> 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'
Een gedetailleerde beschrijving is te vinden in de docs.
Dit zijn linux-paden. Windows zou analoog moeten werken.
Antwoord 12
Wat voor mij werkte, is het gebruik van sys.path.insert
. Toen heb ik de map gespecificeerd die ik moest gaan. Ik hoefde bijvoorbeeld maar één map omhoog te gaan.
import sys
sys.path.insert(0, '../')
Antwoord 13
Ik denk dat om met alle systemen te werken “ntpath” gebruikt wordt in plaats van “os.path”. Tegenwoordig werkt het goed met Windows, Linux en Mac OSX.
import ntpath
import os
dirname = ntpath.dirname(__file__)
filename = os.path.join(dirname, 'relative/path/to/file/you/want')
Antwoord 14
Van wat anderen suggereren en van pathlibdocumentatie, een eenvoudige en duidelijke oplossing is de volgende (stel dat het bestand waarnaar we moeten verwijzen: 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())
Dit lijkt me een beetje vreemd, want als je some_script.py
verplaatst, kan het pad naar de hoofdmap van ons project veranderen (we zouden parents[4]
). Aan de andere kant vond ik een oplossing die ik verkies op basis van hetzelfde idee.
Stel dat we de volgende mappenstructuur hebben:
Tests
+-- data
¦ L-- users.csv
L-- src
+-- long
¦ L-- module
¦ L-- subdir
¦ L-- some_script.py
+-- main.py
L-- paths.py
Het bestand paths.py
is verantwoordelijk voor het opslaan van de hoofdlocatie van ons project:
from pathlib import Path
PROJECT_ROOT = Path(__file__).parents[1]
Alle scripts kunnen nu paths.PROJECT_ROOT
gebruiken om absolute paden uit de hoofdmap van het project uit te drukken. In src/long/module/subdir/some_script.py
zouden we bijvoorbeeld kunnen hebben:
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())
En alles gaat zoals verwacht:
~/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
Het main.py
-script is simpelweg:
from long.module.subdir import some_script
some_script.hello()
Antwoord 15
Een eenvoudige oplossing zou zijn
import os
os.chdir(os.path.dirname(__file__))
Antwoord 16
Van C:\Users\xyz\myFolder
naar 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)
Uitvoer
C:\Users\xyz\myFolder
C:\Users\xyz\testdata
Antwoord 17
Ik weet niet zeker of dit van toepassing is op sommige van de oudere versies, maar ik geloof dat Python 3.3 native relatieve padondersteuning heeft.
De volgende code zou bijvoorbeeld een tekstbestand moeten maken in dezelfde map als het python-script:
open("text_file_name.txt", "w+t")
(merk op dat er geen voorwaartse of backslash aan het begin mag staan als het een relatief pad is)