Является ли атрибут модуля __file__ абсолютным или относительным? - PullRequest
96 голосов
/ 19 августа 2011

У меня проблемы с пониманием __file__. Из того, что я понимаю, __file__ возвращает абсолютный путь, с которого был загружен модуль.

У меня проблема с производством этого: у меня есть abc.py с одним оператором print __file__, работающим с /d/projects/ python abc.py, возвращает abc.py. работает с /d/ возвращает projects/abc.py. Любые причины почему?

Ответы [ 4 ]

92 голосов
/ 19 августа 2011

Из документации :

__file__ - это путь к файлу, из которого был загружен модуль, если он был загружен из файла.Атрибут __file__ отсутствует для модулей C, которые статически связаны с интерпретатором;для модулей расширения, загружаемых динамически из общей библиотеки, это путь к файлу общей библиотеки.

Из цепочки рассылки , связанной @kindall в комментарии к вопросу:

Я не пытался воспроизвести этот конкретный пример, но причина в том, что нам не нужно вызывать getpwd () при каждом импорте, и мы не хотим иметь какой-то видвнутрипроцессная переменная для кэширования текущего каталога.(getpwd () относительно медленный и иногда может напрямую потерпеть неудачу, и попытка его кешировать имеет определенный риск ошибиться.)

Вместо этого мы делаем код в site.py, который просматривает элементыsys.path и превращает их в абсолютные пути.Однако этот код выполняется до того, как '' вставляется в начало sys.path, поэтому начальное значение sys.path равно ''.

В остальном, рассмотрим sys.path, а нечтобы включить ''.

Итак, если вы находитесь за пределами части sys.path, содержащей модуль, вы получите абсолютный путь .Если вы находитесь внутри части sys.path, содержащей модуль, вы получите относительный путь .

Если вы загрузите модуль в текущем каталоге и текущем каталоге не в sys.path, вы получите абсолютный путь.

Если вы загрузите модуль в текущем каталоге, а текущий каталог будет в sys.path, вы получите относительный путь.

51 голосов
/ 04 апреля 2014

__file__ является абсолютным , начиная с Python 3.4 , за исключением случаев, когда выполняется скрипт непосредственно с использованием относительного пути:

Атрибуты модуля __file__ (и связанные значения) теперь должны всегда содержать абсолютные пути по умолчанию, за единственным исключением __main__.__file__, когда сценарий выполнялся напрямую с использованием относительного пути. (Предоставлено Бреттом Кэнноном в bpo-18416 .)

Не уверен, что он разрешает символические ссылки.

Пример прохождения относительного пути:

$ python script.py
14 голосов
/ 12 мая 2014

Поздний простой пример:

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

В Python-2. * Второй вызов неправильно определяет path.abspath(__file__) на основе текущего каталога:

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

Как отмечает @techtonik, в Python 3.4+ это будет работать нормально, так как __file__ возвращает абсолютный путь.

4 голосов
/ 13 марта 2014

С помощью почты Гвидо, предоставленной @kindall, мы можем понять стандартный процесс импорта как попытку найти модуль в каждом элементе sys.path и файл в результате этого поиска (подробнее в Модули и импорт PyMOTW .).Поэтому, если модуль находится в абсолютном пути в sys.path, результат является абсолютным, но если он находится в относительном пути в sys.path, результат является относительным.

Теперь файл запуска site.pyзаботится о доставке только абсолютного пути в sys.path, кроме начального '', поэтому, если вы не измените его другими способами, кроме установки PYTHONPATH (путь которого также сделан абсолютным, перед префиксом sys.path), выбудет всегда получать абсолютный путь, но когда к модулю обращаются через текущий каталог.

Теперь, если вы обманываете sys.path забавным способом, вы можете получить что угодно.

Например, если выесть пример модуля foo.py в /tmp/ с кодом:

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

Если вы войдете в / tmp, вы получите:

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

Когда в в /home/user, есливы добавляете /tmp ваше PYTHONPATH вы получаете:

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

Даже если вы добавите ../../tmp, оно будет нормализовано и результат будет таким же.

Но если вместоиспользуя PYTHONPATH, вы используете какой-то забавный путь, вы получаете такой же забавный результат, как и причина.

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

Гвидо объясняет в цитированной выше теме, почему python не пытается преобразовать все записи в абсолютные пути:

нам не нужно вызывать getpwd ()при каждом импорте .... getpwd () является относительно медленным и иногда может напрямую потерпеть неудачу,

Таким образом, ваш путь используется как .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...