web-dev-qa-db-fra.com

Chemins relatifs dans Python

Je construis un simple script d'assistance pour le travail qui copiera quelques fichiers de modèle de notre base de code dans le répertoire actuel. Cependant, je n'ai pas le chemin absolu vers le répertoire où sont stockés les modèles. J'ai un chemin relatif à partir du script, mais lorsque j'appelle le script, il le traite comme un chemin relatif au répertoire de travail actuel. Existe-t-il un moyen de spécifier que cette URL relative provient plutôt de l'emplacement du script?

193
baudtack

Dans le fichier qui contient le script, vous voulez faire quelque chose comme ceci:

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

Cela vous donnera le chemin absolu vers le fichier que vous recherchez. Notez que si vous utilisez setuptools, vous devriez probablement utiliser son API de ressources de package .

UPDATE: Je réponds à un commentaire ici pour pouvoir coller un exemple de code. :-)

Ai-je raison de penser que __file__ n'est pas toujours disponible (par exemple, lorsque vous exécutez le fichier directement plutôt que de l'importer)?

Je suppose que vous voulez parler du script __main__ lorsque vous mentionnez que vous exécutez le fichier directement. Si tel est le cas, cela ne semble pas être le cas sur mon système (python 2.5.1 sur 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

Cependant, je sais qu'il y a quelques problèmes avec __file__ sur les extensions C. Par exemple, je peux le faire sur mon 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'

Cependant, cela soulève une exception sur ma machine Windows.

262
Jason Baker

vous avez besoin de os.path.realpath (l'exemple ci-dessous ajoute le répertoire parent à votre chemin)

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

Comme mentionné dans la réponse acceptée

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

Je veux juste ajouter que

la dernière chaîne ne peut pas commencer par la barre oblique inversée, en fait aucune chaîne ne devrait inclure une barre oblique inversée

Cela devrait être quelque chose comme

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

La réponse acceptée peut être trompeuse dans certains cas, veuillez vous référer au lien this pour plus de détails.

48
Ahmed

Considérons mon 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)
13
Fahad Haleem

Voir sys.path Initialisé au démarrage du programme, le premier élément de cette liste, chemin [0], est le répertoire contenant le script utilisé pour appeler l'interpréteur Python.

Utilisez ce chemin comme dossier racine à partir duquel vous appliquez votre chemin relatif

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

Nous sommes en 2018 et Python ont déjà évolué vers le __future__ il y a longtemps. Alors pourquoi ne pas utiliser l’étonnant pathlib avec Python 3.4 pour accomplir la tâche au lieu de lutter avec os, os.path, glob, shutil, etc.

Nous avons donc 3 chemins ici (éventuellement dupliqués):

  • mod_path: qui est le chemin du script d'assistance simple
  • src_path: qui contient un couple de fichiers de modèle en attente de copie.
  • cwd: répertoire actuel , la destination de ces fichiers de modèle.

et le problème est le suivant: nous n’avons pas le chemin complet de src_path, nous ne savons que que c’est chemin relatif vers le mod_path.

Maintenant, résolvons cela avec l'incroyable 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()

À l'avenir, c'est aussi simple que cela. :RÉ


De plus, nous pouvons sélectionner, vérifier et copier/déplacer ces fichiers modèles avec 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

À la place d'utiliser

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

comme dans la réponse acceptée, il serait plus robuste d'utiliser:

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

parce que l'utilisation de __file__ renverra le fichier à partir duquel le module a été chargé, s'il a été chargé à partir d'un fichier. Ainsi, si le fichier avec le script est appelé depuis un autre endroit, le répertoire renvoyé ne sera pas correct.

Ces réponses donnent plus de détails: https://stackoverflow.com/a/31867043/554225 et https://stackoverflow.com/a/50502/554225

5
smiley

Ce code renverra le chemin absolu du script principal.

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

Cela fonctionnera même dans un module.

4
BookOwl

Bonjour tout d’abord, vous devez comprendre les fonctions os.path.abspath (chemin) et os.path.relpath (chemin)

En bref os.path.abspath (chemin) crée un chemin relatif à chemin absol. Et si le chemin fourni est lui-même un chemin absolu, la fonction renvoie le même chemin.

de même os.path.relpath (chemin) crée un chemin absol à chemin relatif. Et si le chemin fourni est lui-même un chemin relatif, la fonction renvoie le même chemin.

l'exemple ci-dessous peut vous permettre de comprendre correctement le concept ci-dessus:

supposons que j'ai un fichier input_file_list.txt qui contient la liste des fichiers d'entrée à traiter par mon script python.

D:\conc\input1.dic

D:\conc\input2.dic

D:\Copyioconc\input_file_list.txt

Si vous voyez la structure de dossiers ci-dessus, input_file_list.txt est présent dans le dossier Copyofconc et les fichiers à traiter par le script python sont présents dans - conc dossier

Mais le contenu du fichier input_file_list.txt est celui présenté ci-dessous:

..\conc\input1.dic

..\conc\input2.dic

Et mon script python est présent dans le lecteur D:.

Et le chemin relatif fourni dans le fichier input_file_list.txt est relatif au chemin de (input_file_list.txt fichier.

Ainsi, lorsque le script python exécutera le répertoire de travail actuel (utilisez os.getcwd () pour obtenir le chemin).

Comme mon chemin relatif est relatif à input_file_list.txt, c’est "D:\Copyofconc", je dois changer le répertoire de travail actuel en "D:\Copyofconc ".

Je dois donc utiliser os.chdir ('D:\Copyofconc'), le répertoire de travail actuel doit donc être "D:\Copyofconc".

Maintenant, pour obtenir les fichiers input1.dic et input2.dic, je vais lire les lignes "..\conc\input1.dic", puis utiliser la commande

input1_path = os.path.abspath ('..\conc\input1.dic') (pour changer le chemin relatif en chemin absolu. Ici, le répertoire de travail actuel est "D:\Copyofconc", le fichier ".\conc\input1.dic" sera accessible par rapport à "D:\Copyofconc")

so input1_path doit être "D:\conc\input1.dic"

3
Chandrajyoti Das

Une alternative qui fonctionne pour moi:

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

Ce qui a fonctionné pour moi est d'utiliser sys.path.insert. Ensuite, j'ai spécifié le répertoire dans lequel je devais aller. Par exemple, je devais simplement monter un répertoire.

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