Я хочу определить, изменился ли модуль. Теперь, используя inotify, просто, вам просто нужно знать каталог, из которого вы хотите получать уведомления.
Как получить путь к модулю в python?
Я хочу определить, изменился ли модуль. Теперь, используя inotify, просто, вам просто нужно знать каталог, из которого вы хотите получать уведомления.
Как получить путь к модулю в python?
import a_module
print(a_module.__file__)
На самом деле даст вам путь к файлу .pyc, который был загружен, по крайней мере, в Mac OS X. Поэтому я думаю, что вы можете сделать:
import os
path = os.path.abspath(a_module.__file__)
Вы также можете попробовать:
path = os.path.dirname(a_module.__file__)
Чтобы получить каталог модуля.
В python есть модуль 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__
вернет путь абсолютный модуля. Однако, учитывая следующее script foo.py:
#foo.py
print '__file__', __file__
Вызов с помощью "python foo.py" Вернется просто "foo.py". Если вы добавите shebang:
#!/usr/bin/python
#foo.py
print '__file__', __file__
и вызовите его с помощью. /foo.py, он вернет './foo.py'. Вызов из другого каталога (например, поместите foo.py в строку каталога), затем вызывая либо
python bar/foo.py
или добавление shebang и выполнение файла напрямую:
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, указывающую на файл_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
@SummerBreeze упоминает, используя inspect модуль.
Кажется, что это хорошо работает и довольно сжато для импортированных модулей:
import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)
послушно возвращает абсолютный путь. Однако для нахождения пути к выполняемому в настоящее время script, я не видел способа его использования.
Я не понимаю, почему никто не говорит об этом, но для меня самым простым решением является использование imp.find_module ( "modulename" ) (документация здесь):
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))
Преимущество этого метода над "проверкой" заключается в том, что вам не нужно импортировать модуль, чтобы он работал, и вы можете использовать строку во вводе. Полезно при проверке модулей, вызываемых в другом script, например.
ИЗМЕНИТЬ
В python3 модуль importlib
должен делать:
Doc importlib.util.find_spec
:
Возвращает спецификацию для указанного модуля.
Сначала, sys.modules проверяется, был ли модуль уже импортирован. Если это так, то возвращается sys.modules [name]. spec. Если это произойдет установите значение None, затем 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
import module
print module.__path__
Пакеты поддерживают еще один специальный атрибут
__path__
. Это инициализируется как список, содержащий имя каталога, содержащего пакеты__init__.py
перед выполнением кода в этом файле. Эта переменная может быть изменена; это влияет на будущие поиски модулей и подпакетов, содержащихся в пакете.Хотя эта функция часто не нужна, ее можно использовать для расширения набор модулей, найденных в пакете.
Итак, я потратил немало времени, пытаясь сделать это с помощью py2exe Проблема заключалась в том, чтобы получить базовую папку script, выполнялась ли она как python script или как исполняемый файл 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 os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>
Если единственное предостережение при использовании __file__
- это когда текущий относительный каталог пуст (т.е. при запуске как script из того же каталога, где находится script), тогда тривиальное решение:
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
Трюк находится в or '.'
после вызова dirname()
. Он устанавливает dir как .
, что означает текущий каталог и является допустимым каталогом для любой связанной с ним функции.
Таким образом, использование abspath()
действительно не требуется. Но если вы все равно используете его, трюк не нужен: abspath()
принимает пустые пути и правильно интерпретирует его как текущий каталог.
Я хотел бы внести свой вклад в один общий сценарий (в Python 3) и изучить несколько подходов к нему.
Встроенная функция open() принимает относительный или абсолютный путь в качестве первого аргумента. Относительный путь обрабатывается как относительный к текущему рабочему каталогу, хотя рекомендуется передавать абсолютный путь к файлу.
Проще говоря, если вы запустите файл сценария со следующим кодом, это не гарантирует, что файл example.txt
будет создан в том же каталоге, где находится файл сценария:
with open('example.txt', 'w'):
pass
Чтобы исправить этот код, нам нужно получить путь к сценарию и сделать его абсолютным. Чтобы обеспечить абсолютный путь, мы просто используем функцию os.path.realpath(). Чтобы получить путь к сценарию, есть несколько общих функций, которые возвращают различные результаты пути:
os.getcwd()
os.path.realpath('example.txt')
sys.argv[0]
__file__
Обе функции os.getcwd() и os.path.realpath() возвращают результаты пути на основе текущего рабочего каталога. Вообще не то, что мы хотим. Первым элементом списка sys.argv является путь к корневому сценарию (сценарию, который вы запускаете) независимо от того, вызываете ли вы этот список в самом корневом сценарии или в каком-либо из его модулей. Это может пригодиться в некоторых ситуациях. Переменная __file__ содержит путь к модулю, из которого она была вызвана.
Следующий код правильно создает файл example.txt
в том же каталоге, где находится скрипт:
filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')
with open(filepath, 'w'):
pass
Если вы хотите сделать это динамически в "программе", попробуйте этот код:
Могу сказать, вы можете не знать точное имя модуля, чтобы "жестко" его.
Он может быть выбран из списка или может не выполняться в настоящее время для использования __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 Так как это в программе, его можно легко добавить в метод или модуль для повторного использования.
Из модулей пакета 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, я изменил код.
Если вы хотите узнать абсолютный путь из вашего скрипта, вы можете использовать объект Path:
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__
.
Надеюсь это поможет!