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 .