Как получить путь к модулю?
Вопрос
Я хочу определить, изменился ли модуль.Теперь использовать inotify очень просто: вам просто нужно знать каталог, из которого вы хотите получать уведомления.
Как получить путь к модулю в Python?
Решение
import a_module
print(a_module.__file__)
На самом деле даст вам путь к файлу .pyc, который был загружен, по крайней мере, в Mac OS X. Так что я думаю, вы можете сделать:
import os
path = os.path.dirname(a_module.__file__)
Вы также можете попробовать:
path = os.path.abspath(a_module.__file__)
Получить каталог модуля.
Другие советы
Есть inspect
модуль на питоне.
Официальная документация
Модуль Inspect предоставляет несколько полезных функций, чтобы помочь получить информацию о живых объектах, таких как модули, классы, методы, функции, трассировки, объекты кадров и объекты кода.Например, это может помочь вам изучить содержимое класса, получить исходный код метода, извлечь и отформатировать список аргументов для функции или получить всю информацию, необходимую для отображения подробного трасса.
Пример:
>>> import os
>>> import inspect
>>> inspect.getfile(os)
'/usr/lib64/python2.7/os.pyc'
>>> inspect.getfile(inspect)
'/usr/lib64/python2.7/inspect.pyc'
>>> os.path.dirname(inspect.getfile(inspect))
'/usr/lib64/python2.7'
Как уже говорилось в других ответах, лучший способ сделать это - с помощью __file__
(еще раз продемонстрировано ниже).Однако есть важная оговорка, заключающаяся в том, что __file__
НЕ существует, если вы запускаете модуль самостоятельно (т.е.как __main__
).
Например, предположим, что у вас есть два файла (оба находятся в вашем PYTHONPATH):
#/path1/foo.py
import bar
print(bar.__file__)
и
#/path2/bar.py
import os
print(os.getcwd())
print(__file__)
Запуск foo.py даст результат:
/path1 # "import bar" causes the line "print(os.getcwd())" to run
/path2/bar.py # then "print(__file__)" runs
/path2/bar.py # then the import statement finishes and "print(bar.__file__)" runs
ОДНАКО, если вы попытаетесь запустить bar.py самостоятельно, вы получите:
/path2 # "print(os.getcwd())" still works fine
Traceback (most recent call last): # but __file__ doesn't exist if bar.py is running as main
File "/path2/bar.py", line 3, in <module>
print(__file__)
NameError: name '__file__' is not defined
Надеюсь это поможет.Это предостережение стоило мне много времени и путаницы при тестировании других представленных решений.
Я постараюсь также рассмотреть несколько вариантов этого вопроса:
<Ол>(Некоторые из этих вопросов были заданы в SO, но были закрыты как дубликаты и перенаправлены здесь.)
Предостережения об использовании __ file __
Для модуля, который вы импортировали:
import something
something.__file__
вернет абсолютный путь модуля. Однако, учитывая следующий скрипт foo.py:
#foo.py
print '__file__', __file__
Вызов его с помощью «python foo.py» вернет просто «foo.py». Если вы добавите Шебанг:
#!/usr/bin/python
#foo.py
print '__file__', __file__
и вызовите его с помощью ./foo.py, он вернет './foo.py'. Вызов его из другого каталога (например, поместите foo.py в строку каталога), а затем вызов
python bar/foo.py
или добавление шебанга и непосредственное выполнение файла:
bar/foo.py
вернет 'bar / foo.py' ( относительный путь).
Поиск каталога
Теперь перейдя оттуда к каталогу, os.path.dirname (__ file __)
также может быть сложным. По крайней мере, в моей системе она возвращает пустую строку, если вы вызываете ее из того же каталога, что и файл. напр.
# foo.py
import os
print '__file__ is:', __file__
print 'os.path.dirname(__file__) is:', os.path.dirname(__file__)
выведет:
__file__ is: foo.py
os.path.dirname(__file__) is:
Другими словами, он возвращает пустую строку, поэтому это не кажется надежным, если вы хотите использовать его для текущего файла (в отличие от файла из импортированный модуль). Чтобы обойти это, вы можете обернуть это в вызов abspath:
# foo.py
import os
print 'os.path.abspath(__file__) is:', os.path.abspath(__file__)
print 'os.path.dirname(os.path.abspath(__file__)) is:', os.path.dirname(os.path.abspath(__file__))
который выводит что-то вроде:
os.path.abspath(__file__) is: /home/user/bar/foo.py
os.path.dirname(os.path.abspath(__file__)) is: /home/user/bar
Обратите внимание, что abspath () НЕ разрешает символические ссылки. Если вы хотите сделать это, используйте вместо этого realpath (). Например, создание символической ссылки file_import_testing_link, указывающей на file_import_testing.py, со следующим содержимым:
import os
print 'abspath(__file__)',os.path.abspath(__file__)
print 'realpath(__file__)',os.path.realpath(__file__)
выполнение будет печатать абсолютные пути что-то вроде:
abspath(__file__) /home/user/file_test_link
realpath(__file__) /home/user/file_test.py
file_import_testing_link - > file_import_testing.py р>
Использование inspect
@SummerBreeze упоминает об использовании модуля inspect .
Похоже, это хорошо работает и довольно кратко для импортированных модулей:
import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)
послушно возвращает абсолютный путь. Однако, чтобы найти путь к исполняемому в данный момент скрипту, я не нашел способа его использовать.
Я не понимаю, почему никто об этом не говорит, но для меня самое простое решение — использовать imp.find_module("имя_модуля") (документация здесь):
import imp
imp.find_module("os")
Он дает кортеж с путем во второй позиции:
(<open file '/usr/lib/python2.7/os.py', mode 'U' at 0x7f44528d7540>,
'/usr/lib/python2.7/os.py',
('.py', 'U', 1))
Преимущество этого метода перед «проверкой» заключается в том, что вам не нужно импортировать модуль, чтобы он работал, и вы можете использовать строку на входе.Полезно, например, при проверке модулей, вызванных в другом скрипте.
РЕДАКТИРОВАТЬ:
В Python3 importlib
модуль должен сделать:
Док. importlib.util.find_spec
:
Возвращает спецификацию для указанного модуля.
Сначала sys.modules проверяется, был ли уже импортирован модуль.Если да, то sys.modules[имя].спецификация возвращается.Если это не установлено, то ValueError поднимается.Если модуль не находится в Sys.Modules, то sys.meta_path ищет подходящую спецификацию со значением «пути», данным искателям.Ни один не возвращается, если спецификация не может быть найдена.
Если имя предназначено для подмодуля (содержит точку), родительский модуль автоматически импортируется.
Аргументы имени и пакета работают так же, как importlib.import_module().Другими словами, работают относительные имена модулей (с точкой в начале).
Это было тривиально.
У каждого модуля есть переменная __ file __
, которая показывает относительный путь от того места, где вы сейчас находитесь.
Следовательно, получить каталог для модуля, чтобы уведомить его, просто:
os.path.dirname(__file__)
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)
Утилита командной строки
Вы можете настроить его на утилиту командной строки,
python-which <package name>
<Ч>
Создайте / usr / local / bin / python-which
#!/usr/bin/env python
import importlib
import os
import sys
args = sys.argv[1:]
if len(args) > 0:
module = importlib.import_module(args[0])
print os.path.dirname(module.__file__)
Сделайте его исполняемым
sudo chmod +x /usr/local/bin/python-which
Так что я потратил немало времени, пытаясь сделать это с py2exe Проблема заключалась в том, чтобы получить базовую папку сценария, независимо от того, выполнялся ли он как сценарий python или как исполняемый файл py2exe. Кроме того, чтобы он работал независимо от того, запускается ли он из текущей папки, другой папки или (это было наиболее сложно) из системного пути.
В конце концов я использовал этот подход, используя sys.frozen в качестве индикатора работы в py2exe:
import os,sys
if hasattr(sys,'frozen'): # only when running in py2exe this exists
base = sys.prefix
else: # otherwise this is a regular python script
base = os.path.dirname(os.path.realpath(__file__))
import module
print module.__path__
Пакеты поддерживают еще один специальный атрибут,
__ path __
. Это инициализируется как список, содержащий имя каталога, содержащего пакет & # 8217; s__ init __. py
перед выполнением кода в этом файле. Эта переменная может быть изменена; это влияет на будущие поиски модули и подпакеты, содержащиеся в упаковке.Хотя эта функция не требуется часто, ее можно использовать для расширения набор модулей найден в пакете.
вы можете просто импортировать свой модуль затем нажмите на его имя, и вы получите его полный путь
>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>
Если единственное предостережение относительно использования __ file __
- это когда текущий относительный каталог пуст (то есть, когда он запускается как скрипт из того же каталога, где находится скрипт), тогда тривиальное решение: р>
import os.path
mydir = os.path.dirname(__file__) or '.'
full = os.path.abspath(mydir)
print __file__, mydir, full
И результат:
$ python teste.py
teste.py . /home/user/work/teste
Трюк в или '.'
после вызова dirname ()
. Он устанавливает каталог как .
, что означает текущий каталог , и является допустимым каталогом для любой связанной с путем функции.
Таким образом, использование abspath ()
действительно не нужно. Но если вы все равно его используете, уловка не нужна: abspath ()
принимает пустые пути и правильно интерпретирует его как текущий каталог.
Я хотел бы внести свой вклад в один распространенный сценарий (в Python 3) и изучить несколько подходов к нему.
Встроенная функция открыть() принимает относительный или абсолютный путь в качестве первого аргумента.Относительный путь рассматривается как относительно текущего рабочего каталога хотя поэтому рекомендуется передавать абсолютный путь к файлу.
Проще говоря, если вы запустите файл сценария со следующим кодом, это нет гарантировал, что example.txt
файл будет создан в том же каталоге, где находится файл сценария:
with open('example.txt', 'w'):
pass
Чтобы исправить этот код, нам нужно получить путь к скрипту и сделать его абсолютным.Чтобы обеспечить абсолютный путь, мы просто используем ОС.путь.реальный путь() функция.Чтобы получить путь к скрипту, существует несколько общих функций, которые возвращают различные результаты пути:
os.getcwd()
os.path.realpath('example.txt')
sys.argv[0]
__file__
Обе функции os.getcwd() и ОС.путь.реальный путь() результаты обратного пути на основе текущий рабочий каталог.В общем, это не то, что мы хотим.Первый элемент sys.argv список - это путь к корневому скрипту (скрипт, который вы запускаете) независимо от того, вызываете ли вы список в самом корневом скрипте или в каком-либо из его модулей.Это может пригодиться в некоторых ситуациях.А __файл__ переменная содержит путь к модулю, из которого она была вызвана.
Следующий код правильно создает файл example.txt
в том же каталоге, где находится скрипт:
filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')
with open(filepath, 'w'):
pass
Внутри модулей пакета python мне нужно было сослаться на файл, который находился в том же каталоге, что и пакет. Пример.
some_dir/
maincli.py
top_package/
__init__.py
level_one_a/
__init__.py
my_lib_a.py
level_two/
__init__.py
hello_world.py
level_one_b/
__init__.py
my_lib_b.py
Итак, выше я должен был вызвать maincli.py из модуля my_lib_a.py, зная, что top_package и maincli.py находятся в одном каталоге. Вот как я могу получить путь к maincli.py:
import sys
import os
import imp
class ConfigurationException(Exception):
pass
# inside of my_lib_a.py
def get_maincli_path():
maincli_path = os.path.abspath(imp.find_module('maincli')[1])
# top_package = __package__.split('.')[0]
# mod = sys.modules.get(top_package)
# modfile = mod.__file__
# pkg_in_dir = os.path.dirname(os.path.dirname(os.path.abspath(modfile)))
# maincli_path = os.path.join(pkg_in_dir, 'maincli.py')
if not os.path.exists(maincli_path):
err_msg = 'This script expects that "maincli.py" be installed to the '\
'same directory: "{0}"'.format(maincli_path)
raise ConfigurationException(err_msg)
return maincli_path
На основании публикации PlasmaBinturong я изменил код.
Если вы хотите сделать это динамически в программе " попробуйте этот код:
Моя точка зрения такова, что вы можете не знать точное название модуля для «жесткого кода» Это.
Он может быть выбран из списка или может не работать в данный момент для использования __file __.
(я знаю, это не будет работать в Python 3)
global modpath
modname = 'os' #This can be any module name on the fly
#Create a file called "modname.py"
f=open("modname.py","w")
f.write("import "+modname+"\n")
f.write("modpath = "+modname+"\n")
f.close()
#Call the file with execfile()
execfile('modname.py')
print modpath
<module 'os' from 'C:\Python27\lib\os.pyc'>
Я пытался избавиться от " глобального " проблема, но обнаружил случаи, когда это не сработало Я думаю, что "execfile ()" можно эмулировать в Python 3 Поскольку это в программе, его можно легко вставить в метод или модуль для повторного использования.
Если вы хотите узнать абсолютный путь из своего скрипта, вы можете использовать путь объект:
from pathlib import Path
print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())
Возвращает новый объект пути, представляющий текущий каталог (как возвращено os.getcwd ())
Сделайте путь абсолютным, разрешив любые символические ссылки. Возвращается новый объект пути:
Если вы хотите получить корневой путь пакета из любого из его модулей, работает следующее (проверено на Python 3.6):
from . import __path__ as ROOT_PATH
print(ROOT_PATH)
На основной путь __ init __. py
также можно ссылаться, используя вместо этого __ file __
.
Надеюсь, это поможет!