Как получить путь к модулю?

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

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

Проверьте modulefinder: docs.python.org/library/modulefinder.html

user1256374 08.03.2012 10:19

Если вы все еще просматриваете этот сайт, обновите правильный ответ на это. Это намного чище, чем предлагаемое решение, и работает также в тех случаях, когда __file__ не установлен.

erikbwork 18.12.2013 15:16

@ erikb85: это не только чище; Решение на основе inspect также работает в случае execfile(), когда __file__ автоматически выдает неправильное имя.

jfs 21.02.2014 17:49
import pathlib, module; pathlib.Path(module.__file__).resolve().parent Это не зависит от платформы
MortenB 16.03.2018 14:48

модуль .__ путь __ [0]

iMath 19.08.2018 05:45

Я использую записную книжку Jupter, и у меня есть другой файл записной книжки, например GetData, и есть класс ABC. Я импортировал этот класс ABC в другой блокнот from GetData import ABC, но когда я использую inspect.getfile (GetData) или print (GetData .__ file__), я получаю имя ошибки GetData is not defined или attrinute файл not found. Проблема заключается в изменении класса ABC, функция которого вызывается из записной книжки, которая импортирует ее и видит, что результат остается таким же, как в старом файле. Но если я вношу такие же изменения в GetData и запускаю из записной книжки GetData, это отражается.

Invictus 04.09.2020 13:12
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
839
7
744 570
20
Перейти к ответу Данный вопрос помечен как решенный

Ответы 20

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

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

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

os.path.dirname(__file__)

Почти, но не совсем верно - файл - это нет "относительно того места, где вы находитесь сейчас"; когда он относительный (что будет только тогда, когда в sys.path есть относительные пути), он относительно где вы были, когда модуль был загружен.

Charles Duffy 29.10.2008 22:25

Начиная с Python 3.9 __file__ - это всегда абсолютный путь.

Boris 06.10.2020 06:16
Ответ принят как подходящий
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__)

Чтобы получить каталог модуля.

это отвечает, как получить путь к модулю, который вы импортируете, но не к модулю / сценарию, в котором вы находитесь (для сценария, который вы запускаете, __file__ не является полным путем, он относительный). Для файла, в котором я нахожусь, мне пришлось импортировать другой модуль из того же каталога и сделать, как показано здесь. Кто-нибудь знает более удобный способ?

Ben Bryant 19.01.2012 22:11

Я не пробовал, но дает ли self .__ file__ результаты, отличные от __file__?

RobotHumans 05.10.2013 01:01

@hbdgaf уверен, что встроенного self.__file__ не существует

Dan Passaro 06.11.2013 01:24

@BenBryant @hbdgaf os.path.dirname(__file__) отлично работает для меня и возвращает путь abs к каталогу модуля.

Niccolò 18.08.2014 20:14

__DoubleUnderlinedNames__ предназначен для вызова операторами Python или встроенными функциями, поэтому я думаю, что Python должен вызывать атрибут __file__, а не напрямую программистом. Я думаю, что ответ SummerBreeze лучше соответствует этому соглашению.

smwikipedia 05.10.2014 05:05

Я попытался сделать это и получить трассировку: AttributeError: 'module' object has no attribute '__file__'

Dorian Dore 05.04.2015 20:02

@DorianDore Я немного возился с модулями и дошел до решения path = module.__path__.__dict__["_path"][0], но я не уверен, переносимо ли оно или оно не отличается между версиями python. Он работает для меня, в отличие от этого ответа, который дает мне ту же ошибку, а ответ inspect вызывает TypeError: <module 'module' (namespace)> is a built-in module ...

Jezor 04.07.2016 03:15

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

Ali 03.10.2020 12:53
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)

не работает на моем Linux python 2.6, так как __file__ - это просто dir / test.py, abspath включает cwd для завершения имени пути, что не является желаемым результатом, но если вы импортируете модуль, m.__file__ дает желаемый результат.

Ben Bryant 19.01.2012 21:41

Как говорили другие ответы, лучший способ сделать это - использовать __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 

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

В этом случае вы можете использовать sys.argv [0] вместо файл.

Jimothy 14.02.2013 21:41

Это оговорка для конкретной версии? В версиях 2.6 и 2.7 я успешно полагаюсь на файл, который работает файл, когда имя __ == '__ main '. Единственный случай сбоя, который я видел, - это "python -c 'print файл'". Я добавлю, что иногда файл может быть '<stdin>', что происходит, когда IDE, такие как emacs, выполняют текущий буфер.

Paul Du Bois 20.02.2013 01:23

Обратите внимание, что начальные и конечные символы «__» выделяют слово жирным шрифтом, так что имейте это в виду при чтении предыдущих комментариев :-P

Paul Du Bois 20.02.2013 01:24

@PaulDuBois Вы можете окружить его задними тиками: `__file__` становится __file__

fncomp 31.03.2013 00:30
then "print __file__" runs, эй, а что случилось с print os.getcwd() в bar.py при импорте из foo.py с import bar?
n611x007 20.09.2013 14:16

Это здесь. "/path1 # "import bar" causes the line "print os.getcwd()" to run"

mcstrother 20.09.2013 18:34

Как получить NameError? @Paul Du Bois: Я пробовал Python 2.3-3.4, и __file__ определен, но я запускаю файл Python: python a.py, python -ma, ./a.py.

jfs 21.02.2014 17:37

Поэтому я потратил довольно много времени, пытаясь сделать это с помощью 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__))

В питоне есть модуль inspect.

Официальная документация

The inspect module provides several useful functions to help get information about live objects such as modules, classes, methods, functions, tracebacks, frame objects, and code objects. For example, it can help you examine the contents of a class, retrieve the source code of a method, extract and format the argument list for a function, or get all the information you need to display a detailed traceback.

Пример:

>>> 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'

Вы также можете использовать inspect, чтобы получить имя текущего файла; см. stackoverflow.com/a/50905/320036

z0r 24.09.2013 08:57

Я много раз гуглил этот вопрос, и это - самый разумный ответ, который я когда-либо видел! Обновите информацию о inspect.currentframe()

erikbwork 18.12.2013 15:15

подход inspect.getfile() не работает с модулем _io, но работает с модулем io.

smwikipedia 06.10.2014 05:28

Я также постараюсь ответить на несколько вариантов этого вопроса:

  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

или добавив 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, указывающей на 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)

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

inspect.getfile(inspect.currentframe())

(спасибо @jbochi)

inspect.getfile (os) совпадает с os .__ file__ из кода: def getfile (object): "" "Определить, в каком исходном или скомпилированном файле был определен объект." "" if ismodule (object): if hasattr (объект, 'файл'): вернуть объект .__ file__

idanzalz 08.07.2014 16:28

Это должен быть принятый ответ. Спасибо за исчерпывающий ответ.

YSC 02.11.2020 19:04

Если единственное предостережение при использовании __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() принимает пустые пути и правильно интерпретирует его как текущий каталог.

Лучше поменять местами порядок и просто использовать os.path.dirname(os.path.abspath(__file__)), потому что тогда вам вообще не придется беспокоиться об относительных путях. На одну возможность для ошибок меньше.

szali 03.02.2020 11:35
import module
print module.__path__

Packages support one more special attribute, __path__. This is initialized to be a list containing the name of the directory holding the package’s __init__.py before the code in that file is executed. This variable can be modified; doing so affects future searches for modules and subpackages contained in the package.

While this feature is not often needed, it can be used to extend the set of modules found in a package.

Источник

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

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

Return the spec for the specified module.

First, sys.modules is checked to see if the module was already imported. If so, then sys.modules[name].spec is returned. If that happens to be set to None, then ValueError is raised. If the module is not in sys.modules, then sys.meta_path is searched for a suitable spec with the value of 'path' given to the finders. None is returned if no spec could be found.

If the name is for submodule (contains a dot), the parent module is automatically imported.

The name and package arguments work the same as importlib.import_module(). In other words, relative module names (with leading dots) work.

imp НЕ обесценивается в python 2 (текущая версия 2.7.13). imp в Python 3, начиная с версии 3.4. Вместо этого в python 3 следует использовать importlib. Мне нравится это решение, потому что оно работает даже тогда, когда фактический импорт не удастся (например, из-за 64-битного модуля для 32-битного движка)

mdew 21.12.2016 10:57

И ДЕЙСТВИТЕЛЬНО приятно при попытке найти путь к 64-битному sqlite3 и сбой импорта. Идеальный.

rahvin_t 07.12.2018 23:49
importlib.machinery.PathFinder().find_module("os").get_filen‌​ame() Самая короткая альтернатива imp.find_module, которую я нашел в Python3 +. Если кто ищет использование importlib.util.find_spec.
Torxed 24.03.2019 19:10

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

Gouda 09.05.2019 10:07

Из модулей пакета 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 я изменил код.

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

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

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

Я хотел бы внести свой вклад в один общий сценарий (в Python 3) и изучить несколько подходов к нему.

Встроенная функция открытым() принимает в качестве первого аргумента относительный или абсолютный путь. Относительный путь рассматривается как относительно текущего рабочего каталога, поэтому рекомендуется передавать абсолютный путь к файлу.

Проще говоря, если вы запустите файл сценария со следующим кодом, нет гарантирует, что файл 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 является путь к корневому скрипту (сценарий, который вы запускаете) независимо от того, вызываете ли вы список в самом корневом сценарии или в любом из его модулей. Это может пригодиться в некоторых ситуациях. Переменная __файл__ содержит путь к модулю, из которого он был вызван.


Следующий код правильно создает файл example.txt в том же каталоге, где находится скрипт:

filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')

with open(filepath, 'w'):
    pass

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

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>

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

from pathlib import Path

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

cwd () метод

Return a new path object representing the current directory (as returned by os.getcwd())

метод resolve ()

Make the path absolute, resolving any symlinks. A new path object is returned:

Если вы хотите получить корневой путь пакета из любого из его модулей, работает следующее (проверено на 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

Вот быстрый сценарий 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 ~]#

Когда вы импортируете модуль, вы получаете доступ к большому количеству информации. Проверьте 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'>

Другие вопросы по теме