124 votes

Python __file__ attribut absolu ou relatif?

J'ai du mal à comprendre __file__ . D'après ce que j'ai compris, __file__ renvoie le chemin absolu à partir duquel le module a été chargé.

J'ai des problèmes pour produire ceci: j'ai abc.py avec une déclaration print __file__ , allant de /d/projects/ python abc.py retours abc.py . en cours d'exécution de /d/ retours projects/abc.py . Des raisons pour lesquelles?

101voto

agf Points 45052

__file__ est le chemin du fichier à partir de laquelle le module a été chargé, si il a été chargé à partir d'un fichier. L' __file__ attribut n'est pas présent pour les modules C qui sont liés statiquement dans l'interprète; pour l'extension des modules chargés dynamiquement à partir d'une bibliothèque partagée, c'est le chemin de la bibliothèque partagée de fichier.

À partir de la liste de diffusion thread lié par @kindall dans un commentaire à la question suivante:

Je n'ai pas essayé de reproduire cet exemple particulier, mais la raison en est que nous ne voulons pas avoir à appeler getpwd() sur chaque importation, ni ne nous veulent avoir un certain type de variable de processus à mettre en cache le courant répertoire. (getpwd() est relativement lente et peut parfois échouer carrément, et en essayant de mettre en cache il y a un certain risque de se tromper.)

Ce que nous faisons au lieu de cela, est code site.py qui marche sur les éléments de sys.chemin d'accès et les transforme en des chemins absolus. Cependant l'exécution de ce code avant " est insérée à l'avant de sys.chemin, de sorte que la première la valeur de sys.chemin d'accès est ".

Pour le reste, envisager sys.path de ne pas inclure ''.

Donc, si vous n'êtes pas à l'intérieur de la partie de l' sys.path qui contient le module, vous aurez un chemin d'accès absolu. Si vous êtes à l'intérieur de la partie de l' sys.path qui contient le module, vous aurez un chemin d'accès relatif.

Si vous chargez un module dans le répertoire courant et le répertoire courant n'est pas en sys.path, vous obtiendrez un chemin d'accès absolu.

Si vous chargez un module dans le répertoire courant et le répertoire en cours est en sys.path, vous obtiendrez un chemin d'accès relatif.

62voto

techtonik Points 2945

__file__ est toujours absolu depuis Python 3.4 . Je ne sais pas si cela résout les liens symboliques.

19voto

SimplyKnownAsG Points 117

Exemple simple tardif:

 from os import path, getcwd, chdir

def print_my_path():
    print('cwd:     {}'.format(getcwd()))
    print('__file__:{}'.format(__file__))
    print('abspath: {}'.format(path.abspath(__file__)))

print_my_path()

chdir('..')

print_my_path()
 

Sous Python-2. *, Le deuxième appel détermine de manière incorrecte le path.abspath(__file__) fonction du répertoire en cours:

 cwd:     C:\codes\py
__file__:cwd_mayhem.py
abspath: C:\codes\py\cwd_mayhem.py
cwd:     C:\codes
__file__:cwd_mayhem.py
abspath: C:\codes\cwd_mayhem.py
 

Comme l'a noté @techtonik, dans Python 3.4+, cela fonctionnera très bien puisque __file__ renvoie un chemin absolu.

5voto

marcz Points 414

Avec l'aide de l'Guido mail fournie par @kindall, nous pouvons comprendre la norme processus d'importation que d'essayer de trouver le module de chacun des membres de l' sys.path, et le fichier comme étant le résultat de cette recherche (plus de détails dans PyMOTW Modules et les Importations.). Donc, si le module est situé dans un chemin d'accès absolu en sys.path le résultat est absolue, mais si elle est située dans un chemin relatif en sys.path le résultat est relatif.

Maintenant l' site.py fichier de démarrage prend soin de ne fournir que de chemin d'accès absolu en sys.path, à l'exception du premier '', donc si vous ne l'avez pas changé par d'autres moyens que de fixer le PYTHONPATH (dont le chemin d'accès sont également fait absolue, avant la préfixation sys.path), vous obtiendrez toujours un chemin absolu, mais lorsque le module est accessible via le répertoire courant.

Maintenant, si vous vous leurrez sys.chemin dans une drôle de façon, vous pouvez obtenir quoi que ce soit.

À titre d'exemple, si vous avez un exemple de module foo.py en /tmp/ avec le code:

import sys
print(sys.path)
print (__file__)

Si vous allez dans /tmp, vous bénéficiez de:

>>> import foo
['', '/tmp', '/usr/lib/python3.3', ...]
./foo.py

Lorsque en en /home/user, si vous ajoutez /tmp votre PYTHONPATH vous obtenez:

>>> import foo
['', '/tmp', '/usr/lib/python3.3', ...]
/tmp/foo.py

Même si vous ajoutez ../../tmp, il sera normalisé et le résultat est le même.

Mais si au lieu d'utiliser PYTHONPATH vous utilisez directement drôles de chemin vous obtenez un résultat aussi drôle que la cause.

>>> import sys
>>> sys.path.append('../../tmp')
>>> import foo
['', '/usr/lib/python3.3', .... , '../../tmp']
../../tmp/foo.py

Guido explique dans la citée ci-dessus fil, pourquoi python ne pas essayer de transformer toutes les entrées dans les chemins d'accès absolus:

nous ne voulons pas avoir à appeler getpwd() sur chaque importation .... getpwd() est relativement lente et peut parfois échouer le coup,

Si votre chemin est utilisé comme il est.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X