How to retrieve a module's path?

Я хочу определить, изменился ли модуль. Теперь использовать inotify просто, вам нужно знать каталог, из которого вы хотите получать уведомления.

Как мне получить путь к модулю в Python?

26 ответов

Решение
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 

Надеюсь это поможет. Это предостережение стоило мне много времени и путаницы при тестировании других представленных решений.

Я попытаюсь решить несколько вариантов и по этому вопросу:

  1. найти путь к вызываемому скрипту
  2. найти путь к исполняемому в данный момент скрипту
  3. найти каталог вызываемого скрипта

(Некоторые из этих вопросов были заданы на 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

Используя осмотреть

@SummerBreeze упоминает об использовании модуля проверки.

Похоже, это хорошо работает и довольно кратко для импортированных модулей:

import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)

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

Я не понимаю, почему никто не говорит об этом, но для меня самое простое решение - использовать 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))

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

РЕДАКТИРОВАТЬ:

В python3 importlib Модуль должен делать:

Док о importlib.util.find_spec:

Вернуть спецификацию для указанного модуля.

Сначала проверяется sys.modules, чтобы убедиться, что модуль уже был импортирован. Если это так, то sys.modules [имя].спецификация возвращается. Если для этого параметра установлено значение None, то вызывается ValueError. Если модуль отсутствует в sys.modules, то в sys.meta_path ищется подходящая спецификация со значением 'path', заданным для искателей. Ни один не возвращается, если никакая спецификация не могла быть найдена.

Если имя для субмодуля (содержит точку), родительский модуль автоматически импортируется.

Аргументы name и package работают так же, как importlib.import_module(). Другими словами, относительные имена модулей (с начальными точками) работают.

Это было тривиально.

Каждый модуль имеет __file__ переменная, которая показывает относительный путь от того, где вы находитесь прямо сейчас.

Таким образом, получить каталог для модуля, чтобы уведомить его просто:

os.path.dirname(__file__)
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)
import module
print module.__path__

Пакеты поддерживают еще один специальный атрибут, __path__, Это инициализируется как список, содержащий имя каталога, содержащего пакет __init__.py перед выполнением кода в этом файле. Эта переменная может быть изменена; это влияет на последующий поиск модулей и подпакетов, содержащихся в пакете.

Хотя эта функция не требуется часто, ее можно использовать для расширения набора модулей, найденных в пакете.

Источник

Если вы хотите получить путь к модулю, не загружая его:

      import importlib.util

print(importlib.util.find_spec("requests").origin)

Пример вывода:

      /usr/lib64/python3.9/site-packages/requests/__init__.py

Утилита командной строки

Вы можете настроить его на утилиту командной строки,

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 os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>

Когда вы импортируете модуль, у вас есть доступ к большому количеству информации. Проверять, выписываться dir(a_module). Что касается пути, то здесь есть ужас: a_module.__path__. Вы также можете просто распечатать сам модуль.

>>> import a_module
>>> print(dir(a_module))
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__']
>>> print(a_module.__path__)
['/.../.../a_module']
>>> print(a_module)
<module 'a_module' from '/.../.../a_module/__init__.py'>

Поэтому я потратил немало времени, пытаясь сделать это с 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 logging
>>> print(logging)
<module 'logging' from 'C:\\Users\\Mike\\AppData\\Local\\Programs\\Python\\Python39\\lib\\logging\\__init__.py'>

Если вы хотите получить корневой путь пакета из любого из его модулей, работает следующее (проверено на Python 3.6):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

Главный __init__.py путь также может быть указан с помощью __file__ вместо.

Надеюсь это поможет!

Если вы установили его с помощью pip, "pip show" отлично работает ('Location')

$ pip показать detectron2

Name: detectron2
Version: 0.1
Summary: Detectron2 is FAIR next-generation research platform for object detection and segmentation.
Home-page: https://github.com/facebookresearch/detectron2
Author: FAIR
Author-email: None
License: UNKNOWN
Location: /home/ubuntu/anaconda3/envs/pytorch_p36/lib/python3.6/site-packages
Requires: yacs, tabulate, tqdm, pydot, tensorboard, Pillow, termcolor, future, cloudpickle, matplotlib, fvcore

Если вы хотите узнать абсолютный путь из вашего скрипта, вы можете использовать объект Path:

from pathlib import Path

print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())

метод cwd ()

Возвращает новый объект пути, представляющий текущий каталог (как возвращено os.getcwd())

метод resol ()

Сделайте путь абсолютным, разрешив любые символические ссылки. Новый путь объекта возвращается:

Если единственное предостережение об использовании __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

Хитрость в or '.' после dirname() вызов. Это устанавливает каталог как ., что означает текущий каталог и является допустимым каталогом для любой связанной с путем функции.

Таким образом, используя 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

Современное (Python >= 3.7) решение этой проблемы:importlib.resources.files()

      from importlib import resources
resources.files(package_name)
# => WindowsPath("C:\Path\to\your\package\")

Из модулей пакета Python я должен был ссылаться на файл, который находился в том же каталоге, что и пакет. Ex.

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, я изменил код.

Если ваш импорт представляет собой пакет сайта (например,pandas) Я рекомендую это, чтобы получить его каталог (не работает, если импорт является модулем, например, напримерpathlib):

      from importlib import resources  # part of core Python
import pandas as pd

package_dir = resources.path(package=pd, resource="").__enter__()

В общем, importlib.resources можно рассматривать, когда задача связана с доступом к путям/ресурсам пакета сайта.

Если пользовались, то можно позвонить pip show, но вы должны вызывать его, используя конкретную версию, которую вы используете. Например, все они могут давать разные результаты:

      $ python -m pip show numpy
$ python2.7 -m pip show numpy
$ python3 -m pip show numpy

Location: /System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python

Не просто беги $ pip show numpy, потому что нет гарантии, что он будет таким же pip это другое python версии звонят.

Здесь я печатаю путь к пакету cProfile : -

      import cProfile
import os
path = os.path.abspath(cProfile.__file__)
print(path)

Если вы хотите сделать это динамически в "программе", попробуйте этот код:
Я хочу сказать, что вы можете не знать точное название модуля, чтобы "жестко" его кодировать. Он может быть выбран из списка или может не работать в данный момент для использования __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, так как это в программе, его можно легко поместить в метод или модуль для повторное использование.

Вот быстрый сценарий bash на случай, если он кому-то пригодится. Я просто хочу установить переменную среды, чтобы я могpushd к коду.

#!/bin/bash
module=${1:?"I need a module name"}

python << EOI
import $module
import os
print os.path.dirname($module.__file__)
EOI

Пример оболочки:

[root@sri-4625-0004 ~]# export LXML=$(get_python_path.sh lxml)
[root@sri-4625-0004 ~]# echo $LXML
/usr/lib64/python2.7/site-packages/lxml
[root@sri-4625-0004 ~]#
Другие вопросы по тегам