Je voudrais voir quelle est la meilleure façon de déterminer le répertoire de script actuel en python?
J'ai découvert qu'en raison des nombreuses façons d'appeler du code python, il est difficile de trouver une bonne solution.
Voici quelques problèmes:
__file__
n'est pas défini si le script est exécuté avecexec
,execfile
__module__
est défini uniquement dans les modules
Cas d'utilisation:
./myfile.py
python myfile.py
./somedir/myfile.py
python somedir/myfile.py
execfile('myfile.py')
(à partir d'un autre script, qui peut se trouver dans un autre répertoire et qui peut avoir un autre répertoire en cours.
Je sais qu'il n'y a pas de solution parfaite, mais je recherche la meilleure approche qui résout la plupart des cas.
L'approche la plus utilisée est os.path.dirname(os.path.abspath(__file__))
mais cela ne fonctionne vraiment pas si vous exécutez le script à partir d'un autre avec exec()
.
avertissement
Toute solution qui utilise le répertoire actuel échouera, cela peut être différent selon la façon dont le script est appelé ou il peut être modifié à l'intérieur du script en cours d'exécution.
python
pythonpath
dirname
bogdan
la source
la source
pathlib
solution de Ron Kalian si vous utilisez python 3.4 ou supérieur: stackoverflow.com/a/48931294/1011724python myfile.py
partir d'un shell, cela fonctionne, mais les deux:!python %
et:!python myfile.py
à l'intérieur de vim échouent avec Le système ne peut pas trouver le chemin spécifié. C'est assez ennuyeux. Quelqu'un peut-il commenter la raison derrière cela et les solutions de contournement potentielles?Réponses:
est en effet le meilleur que vous allez obtenir.
Il est inhabituel d'exécuter un script avec
exec
/execfile
; normalement, vous devez utiliser l'infrastructure du module pour charger des scripts. Si vous devez utiliser ces méthodes, je vous suggère de définir__file__
le paramètre queglobals
vous passez au script afin qu'il puisse lire ce nom de fichier.Il n'y a pas d'autre moyen d'obtenir le nom de fichier dans le code exécuté: comme vous le constatez, le CWD peut être à un endroit complètement différent.
la source
Si vous voulez vraiment couvrir le cas où un script est appelé via
execfile(...)
, vous pouvez utiliser leinspect
module pour déduire le nom de fichier (y compris le chemin). Pour autant que je sache, cela fonctionnera pour tous les cas que vous avez énumérés:la source
chdir()
avant la fonction, cela changera le résultat. L'appel du script python à partir d'un autre répertoire modifiera également le résultat, ce n'est donc pas une bonne solution.os.path.expanduser("~")
est un moyen multiplateforme pour obtenir le répertoire de l'utilisateur. Malheureusement, ce n'est pas la meilleure pratique de Windows pour savoir où coller les données d'application.chdir()
avant d'exécuter le script; il produit un résultat correct. J'ai essayé d'appeler le script à partir d'un autre répertoire et cela fonctionne également. Les résultats sont les mêmes que pour uneinspect.getabsfile()
solution basée sur .Il fonctionne sur CPython, Jython, Pypy. Cela fonctionne si le script est exécuté en utilisant
execfile()
(sys.argv[0]
et les__file__
solutions basées ici échoueraient ici). Cela fonctionne si le script se trouve dans un fichier zip exécutable (/ un œuf) . Cela fonctionne si le script est "importé" (PYTHONPATH=/path/to/library.zip python -mscript_to_run
) à partir d'un fichier zip; il renvoie le chemin de l'archive dans ce cas. Cela fonctionne si le script est compilé dans un exécutable autonome (sys.frozen
). Cela fonctionne pour les liens symboliques (realpath
élimine les liens symboliques). Il fonctionne dans un interprète interactif; il renvoie le répertoire de travail actuel dans ce cas.la source
getabsfile(..)
n'est pas mentionné dans la documentationinspect
? Il apparaît dans la source liée à cette page.getsourcefile()
,getfile()
qui sont documentées.Dans Python 3.4+, vous pouvez utiliser le
pathlib
module plus simple :la source
Path(__file__)
(pas besoin duinspect
module).Path(__file__)
donne/path/to/script/currentscript.py
quand l'OP voulait obtenir/path/to/script/
parent = Path(__file__).resolve().parent
C'est beaucoup plus agréable..joinpath()
(ou l'/
opérateur) pour cela, non+
.L'
os.path...
approche était la «chose faite» dans Python 2.En Python 3, vous pouvez trouver le répertoire du script comme suit:
la source
Path(__file__).parent
. Maiscwd
est un terme impropre, ce n'est pas le répertoire de travail actuel , mais le répertoire du fichier . Ils pourraient être les mêmes, mais ce n'est généralement pas le cas.Il suffit d'utiliser
os.path.dirname(os.path.abspath(__file__))
et d'examiner très attentivement s'il existe un réel besoin pour le cas où ilexec
est utilisé. Cela pourrait être un signe de conception problématique si vous n'êtes pas en mesure d'utiliser votre script comme module.Gardez à l'esprit Zen of Python # 8 , et si vous pensez qu'il y a un bon argument pour un cas d'utilisation où cela doit fonctionner
exec
, alors faites-nous savoir plus de détails sur l'arrière-plan du problème.la source
Aurait
Faites ce que vous voulez? Je ne sais pas exactement ce que vous entendez par le "répertoire de script actuel". Quelle serait la sortie attendue pour les cas d'utilisation que vous avez donnés?
la source
exec('myfile.py')
, de la même manière que__file__
etsys.argv[0]
.Tout d'abord .. quelques cas d'utilisation manquants ici si nous parlons de moyens d'injecter du code anonyme ..
Mais, la vraie question est, quel est votre objectif - essayez-vous d'appliquer une sorte de sécurité? Ou êtes-vous simplement intéressé par ce qui est chargé.
Si vous êtes intéressé par la sécurité , le nom de fichier qui est importé via exec / execfile est sans conséquence - vous devriez utiliser rexec , qui offre ce qui suit:
Cependant, si c'est plus une poursuite académique .. voici quelques approches loufoques que vous pourriez peut-être approfondir un peu ..
Exemples de scripts:
./deep.py
./deeper.py
/tmp/deepest.py
./codespy.py
Production
Bien sûr, c'est une façon gourmande en ressources de le faire, vous traceriez tout votre code. Pas très efficace. Mais je pense que c'est une nouvelle approche car elle continue de fonctionner même si vous vous enfoncez plus profondément dans le nid. Vous ne pouvez pas remplacer 'eval'. Bien que vous puissiez remplacer execfile ().
Notez que cette approche ne couvre que exec / execfile, pas 'import'. Pour un accrochage de charge de «module» de niveau supérieur, vous pourriez être en mesure d'utiliser use sys.path_hooks (avec l'aimable autorisation de PyMOTW).
C'est tout ce que j'ai du haut de ma tête.
la source
Voici une solution partielle, encore meilleure que toutes celles publiées jusqu'à présent.
Maintenant, cela fonctionne tous les appels, mais si quelqu'un utilise
chdir()
pour changer le répertoire actuel, cela échouera également.Remarques:
sys.argv[0]
ne va pas fonctionner, reviendra-c
si vous exécutez le script avecpython -c "execfile('path-tester.py')"
la source
Cela devrait fonctionner dans la plupart des cas:
la source
J'espère que cela aide: - Si vous exécutez un script / module depuis n'importe où, vous pourrez accéder à la
__file__
variable qui est une variable de module représentant l'emplacement du script.D'un autre côté, si vous utilisez l'interpréteur, vous n'avez pas accès à cette variable, où vous obtiendrez un nom
NameError
etos.getcwd()
vous donnera le répertoire incorrect si vous exécutez le fichier ailleurs.Cette solution devrait vous donner ce que vous recherchez dans tous les cas:
Je ne l'ai pas testé à fond, mais cela a résolu mon problème.
la source