¿Es el módulo __file__ atributo absoluto o relativo?

Estoy teniendo problemas para entender __file__ . Por lo que entiendo, __file__ devuelve la ruta absoluta desde la que se cargó el módulo.

Estoy teniendo problemas para producir esto: tengo un abc.py con una statement print __file__ , ejecutando desde /d/projects/ python abc.py devuelve abc.py ejecutando desde /d/ devuelve projects/abc.py ¿Alguna razón por la que?

De la documentación :

__file__ es la ruta del archivo desde el que se cargó el módulo, si se cargó desde un archivo. El atributo __file__ no está presente para los módulos C que están vinculados estáticamente al intérprete; para los módulos de extensión cargados dinámicamente desde una biblioteca compartida, es la ruta del archivo de la biblioteca compartida.

Desde el hilo de la lista de correo vinculado por @kindall en un comentario a la pregunta:

No he intentado repetir este ejemplo en particular, pero la razón es que no queremos tener que llamar a getpwd () en cada importación ni queremos tener algún tipo de variable en proceso para almacenar en caché el directorio actual. (getpwd () es relativamente lento y, a veces, puede fallar directamente, y tratar de almacenarlo en caché tiene un cierto riesgo de estar equivocado).

Lo que hacemos en su lugar, es el código en site.py que recorre los elementos de sys.path y los convierte en rutas absolutas. Sin embargo, este código se ejecuta antes de que “” se inserte en la parte frontal de sys.path, de modo que el valor inicial de sys.path es “”.

Para el rest de esto, considere que sys.path no incluye '' .

Por lo tanto, si está fuera de la parte de sys.path que contiene el módulo, obtendrá una ruta absoluta . Si está dentro de la parte de sys.path que contiene el módulo, obtendrá una ruta relativa .

Si carga un módulo en el directorio actual, y el directorio actual no está en sys.path , obtendrá una ruta absoluta.

Si carga un módulo en el directorio actual y el directorio actual está en sys.path , obtendrá una ruta relativa.

__file__ es absoluto desde Python 3.4 , excepto cuando se ejecuta un script directamente usando una ruta relativa:

__file__ atributos del módulo __file__ (y los valores relacionados) ahora siempre deben contener rutas absolutas de forma predeterminada, con la única excepción de __main__.__file__ cuando un script se ha ejecutado directamente utilizando una ruta relativa. (Contribución de Brett Cannon en bpo-18416 .)

No estoy seguro si se resuelve enlaces simbólicos sin embargo.

Ejemplo de pasar una ruta relativa:

 $ python script.py 

Ejemplo simple tardío:

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

Bajo Python-2. *, La segunda llamada determina incorrectamente el path.abspath(__file__) basado en el directorio actual:

 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 

Como lo señaló @techtonik, en Python 3.4+, esto funcionará bien ya que __file__ devuelve una ruta absoluta.

Con la ayuda del correo de Guido proporcionado por @kindall, podemos entender el proceso de importación estándar como intentar encontrar el módulo en cada miembro de sys.path , y el archivo como resultado de esta búsqueda (más detalles en los módulos e importaciones de PyMOTW .). Entonces, si el módulo se encuentra en una ruta absoluta en sys.path el resultado es absoluto, pero si se encuentra en una ruta relativa en sys.path el resultado es relativo.

Ahora, el archivo de inicio de site.py se encarga de entregar solo la ruta absoluta en sys.path , excepto la inicial '' , por lo que si no la cambia de otra manera que no sea la configuración de PYTHONPATH (cuya ruta también se hace absoluta, antes del prefijo sys.path ), siempre obtendrá una ruta absoluta, pero cuando se accede al módulo a través del directorio actual.

Ahora, si trucos sys.path de una manera divertida, puedes conseguir cualquier cosa.

Como ejemplo, si tiene un módulo de ejemplo foo.py en /tmp/ con el código:

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

Si entras en / tmp obtienes:

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

Cuando está en /home/user , si agrega /tmp su PYTHONPATH obtiene:

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

Incluso si agrega ../../tmp , se normalizará y el resultado será el mismo.

Pero si en lugar de usar PYTHONPATH usted usa directamente algún camino divertido, obtiene un resultado tan divertido como la causa.

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

Guido explica en el subproceso citado anteriormente, por qué Python no intenta transformar todas las entradas en rutas absolutas:

no queremos tener que llamar a getpwd () en cada importación … getpwd () es relativamente lento y, a veces, puede fallar,

Así que tu camino se usa tal como es .