Является ли атрибут модуля __file__ абсолютным или относительным?
У меня возникли проблемы с пониманием __file__
. Из того, что я понимаю, __file__
возвращает абсолютный путь, из которого был загружен модуль.
У меня возникла проблема с этим: у меня есть abc.py
с одним утверждением print __file__
, начиная с /d/projects/
python abc.py
возвращает abc.py
. от /d/
возвращает projects/abc.py
. Любые причины, по которым?
Ответы
Ответ 1
Из документации:
__file__
- путь к файлу, из которого был загружен модуль, если он был загружен из файла. __file__
отсутствует для модулей C, которые статически связаны с интерпретатором; для модулей расширения, загружаемых динамически из общей библиотеки, это путь к файлу общей библиотеки.
Из ветки списка рассылки, связанной @kindall в комментарии к вопросу:
Я не пытался воспроизвести этот конкретный пример, но причина в том, что нам не нужно вызывать getpwd() при каждом импорте, и мы не хотим иметь какую-то переменную в процессе для кэширования текущего каталога. (getpwd() является относительно медленным и иногда может напрямую потерпеть неудачу, и попытка его кеширования имеет определенный риск ошибиться.)
Вместо этого мы делаем код в site.py, который просматривает элементы sys.path и превращает их в абсолютные пути. Однако этот код выполняется до того, как '' вставляется в начало sys.path, поэтому начальное значение sys.path равно ''.
В остальном, рассмотрите sys.path
чтобы не включать ''
.
Итак, если вы находитесь за пределами части sys.path
, содержащей модуль, вы получите абсолютный путь. Если вы находитесь внутри части sys.path
, содержащей модуль, вы получите относительный путь.
Если вы загрузите модуль в текущем каталоге, а текущий каталог отсутствует в sys.path
, вы получите абсолютный путь.
Если вы загружаете модуль в текущий каталог, а текущий каталог находится в sys.path
, вы получите относительный путь.
Ответ 2
__file__
с Python 3.4, __file__
является абсолютным, за исключением случаев, когда скрипт выполняется напрямую, используя относительный путь:
__file__
модуля __file__
(и связанные с ними значения) теперь должны всегда содержать абсолютные пути по умолчанию, за единственным исключением __main__.__file__
когда сценарий выполняется напрямую с использованием относительного пути. (Предоставлено Бреттом Кэнноном в bpo-18416.)
Не уверен, что он разрешает символические ссылки, хотя.
Пример прохождения относительного пути:
$ python script.py
Ответ 3
Поздний простой пример:
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
С помощью почты Guido, предоставляемой @kindall, мы можем понять стандартный процесс импорта, пытаясь найти модуль в каждом члене sys.path
, и файл в результате этого поиска (подробнее в Модули и импорт PyMOTW.). Поэтому, если модуль находится в абсолютном пути в sys.path
, результат будет абсолютным, но если он находится в относительном пути в sys.path
, результат будет относительным.
Теперь загрузочный файл site.py
обеспечивает доставку только абсолютного пути в sys.path
, за исключением начального ''
, поэтому, если вы не измените его другими способами, кроме установки PYTHONPATH (чей путь также сделан абсолютный, до префикса sys.path
), вы получите всегда абсолютный путь, но когда к модулю будет доступ через текущий каталог.
Теперь, если вы trick 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
Guido объясняет в приведенном выше примере, почему python не пытается преобразовать все записи в абсолютные пути:
мы не хотим называть getpwd() для каждого импорта.... getpwd() относительно медленный и иногда может быть неудачным,
Итак, ваш путь используется как есть.
Ответ 5
if '\\' in __file__: location='\\'.join(__file__.split('\\')[:-1]) #+'\\' #For Fun
elif '/' in __file__: location='/'.join(__file__.split('/')[:-1]) #+'/'
else: print('\\/\\/HAT THE FUCK!!')