如何获取模块的路径?


754

我想检测模块是否已更改。现在,使用inotify很简单,您只需要知道要从中获取通知的目录即可。

如何在python中检索模块的路径?


1

9
如果您仍在此站点上查找,请更新对此的正确答案。它比建议的解决方案更干净,并且在__file__未设置的情况下也可以使用。
erikbwork

3
@ erikb85:它不仅更清洁;inspect基于解决方案的解决方案也适用于静默产生错误名称的execfile()情况__file__
jfs 2014年


import pathlib, module; pathlib.Path(module.__file__).resolve().parent这是与平台
无关的

Answers:


904
import a_module
print(a_module.__file__)

实际上,至少在Mac OS X上,将为您提供已加载的.pyc文件的路径。因此,我想您可以这样做:

import os
path = os.path.abspath(a_module.__file__)

您也可以尝试:

path = os.path.dirname(a_module.__file__)

获取模块的目录。


54
这回答了如何获取导入模块的路径,而不是您所在模块/脚本的路径(对于正在运行的脚本,__file__它不是完整路径,而是相对路径)。对于我所在的文件,我必须从同一目录中导入另一个模块,然后执行此处所示的操作。有谁知道更方便的方法?
本·布莱恩特

5
@hbdgaf很确定没有内置的东西self.__file__
Dan Passaro

26
@BenBryant @hbdgaf os.path.dirname(__file__)对我来说工作正常,并返回模块目录的abs路径。
尼可罗马基

9
我尝试这样做并得到了追溯: AttributeError: 'module' object has no attribute '__file__'
Dorian Dore

5
@DorianDore我有点弄乱了模块并找到了解决方案path = module.__path__.__dict__["_path"][0],但是我不确定它是否可移植,或者在python版本之间也没有区别。它对我inspectTypeError: <module 'module' (namespace)> is a built-in module
有用

279

inspectpython中有模块。

官方文件

检查模块提供了几个有用的功能,以帮助获取有关活动对象的信息,例如模块,类,方法,函数,回溯,框架对象和代码对象。例如,它可以帮助您检查类的内容,检索方法的源代码,提取函数的参数列表并设置其格式或获取显示详细回溯所需的所有信息。

例:

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

7
您也可以使用inspect来获取当前文件的名称。参见stackoverflow.com/a/50905/320036
z0r 2013年

5
我在这个问题上搜索了很多遍,是我见过的最合理的答案!请更新有关inspect.currentframe()
erikbwork

inspect.getfile()方法不适用于模块_io,但适用于模块io
smwikipedia 2014年

70

正如其他答案所说的那样,最好的方法是使用__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 

希望这可以帮助。在测试其他解决方案时,这一警告使我花费了大量时间和困惑。


5
在这种情况下,可以使用sys.argv [0]代替file
Jimothy

4
这是特定于版本的警告吗?在2.6和2.7中,我成功依赖file,当name __ =='__ main ' 时,该文件有效。我看到的唯一失败案例是“ python -c'打印文件 '”。我要补充一点,有时文件可以是'<stdin>',当emacs之类的IDE执行当前缓冲区时会发生这种情况。
Paul Du Bois

1
请注意,开头和结尾的“ __”字符以粗体显示一个单词,因此在阅读前面的注释时请记住这一点:-P
Paul Du Bois

1
@PaulDuBois您可以将其与回__file____file__
圈符一起使用

1
你怎么得到的NameError?@保罗杜波依斯:我试过的Python 2.3〜3.4和__file__定义,但是我运行Python文件:python a.pypython -ma./a.py
jfs 2014年

43

我还将尝试解决此问题的一些变体:

  1. 查找被调用脚本的路径
  2. 查找当前正在执行的脚本的路径
  3. 查找被调用脚本的目录

(其中一些问题已在SO上提出,但已作为重复内容关闭并在此处重定向。)

使用注意事项 __file__

对于已导入的模块:

import something
something.__file__ 

将返回模块的绝对路径。但是,鉴于以下脚本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指向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)

听话地返回绝对路径。但是,为了找到当前正在执行的脚本的路径,我没有找到使用它的方法。


1
inspect.getfile(os)与以下代码中的os .__ file__相同:def getfile(object):“”“找出在其中定义对象的源文件或编译文件。”“”如果ismodule(object):如果hasattr (对象,“ 文件 ”):返回对象。__file__
idanzalz 2014年

4
您可以inspect.getfile(inspect.currentframe())用来获取当前正在运行的脚本的路径。
jbochi

33

我不明白为什么没有人在谈论这个,但是对我来说,最简单的解决方案是使用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 [name]。规格返回。如果恰好将其设置为“无”,则引发ValueError。如果该模块不在sys.modules中,则在sys.meta_path中搜索一个合适的规范,并为发现者提供'path'的值。如果找不到规范,则不返回任何内容。

如果名称是子模块的名称(包含点),则将自动导入父模块。

名称和包参数与importlib.import_module()相同。换句话说,相对的模块名称(带有前导点)起作用。


2
imp在python 2(当前版本2.7.13)中不被贬值。自3.4起,imp在python 3中已贬值。importlib应该在python 3中使用。我喜欢这个解决方案,因为它甚至可以在实际导入失败时起作用(例如,因为用于32位引擎的64位模块)
mdew 2016年

当尝试找到64位sqlite3的路径并导入失败时,这确实非常好。完善。
rahvin_t

2
importlib.machinery.PathFinder().find_module("os").get_filename()imp.find_module我在Python3 +中找到的最短替代方法。如果有人在寻找的用法importlib.util.find_spec
Torxed

此方法无需导入实际模块即可工作,这非常好,因为我使用它来确定要从共享计算机导入哪个版本的模块。
高达

19

这是微不足道的。

每个模块都有一个__file__变量,显示当前位置的相对路径。

因此,获取模块通知目录的方法很简单:

os.path.dirname(__file__)

14
差不多但并不完全正确- 文件不是 “相对于你在正确的现在在哪里”; 当它是相对的(仅当sys.path中存在相对路径时),才是相对于模块加载时的位置
查尔斯·达菲,

17
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)

1
在我的Linux python 2.6上不起作用,因为__file__它只是dir / test.py,abspath涉及cwd来完成路径名,这不是期望的结果,但是如果您导入模块,则会m.__file__给出期望的结果。
本·布莱恩特

10
import module
print module.__path__

程序包支持另一个特殊属性__path__。它被初始化为一个列表,其中包含__init__.py执行该文件中的代码之前包含软件包目录的目录的名称。这个变量可以修改;这样做会影响以后对包中包含的模块和子包的搜索。

尽管通常不需要此功能,但可以使用它扩展软件包中的模块集。

资源


9

命令行实用程序

您可以将其调整为命令行实用程序,

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

7

因此,我花了大量时间尝试使用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__))

7

您可以导入模块,然后点击其名称,然后获取其完整路径

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

4

如果要从包的任何模块中检索包的根路径,则可以进行以下工作(在Python 3.6上测试):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

__init__.py路径也可以通过使用__file__代替。

希望这可以帮助!


3

如果使用的唯一警告__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()调用。它将dir设置为.,表示当前目录并且是任何与路径相关的函数的有效目录。

因此,abspath()并不是真正需要使用。但是,如果仍然使用它,就不需要技巧了:abspath()接受空白路径并将其正确解释为当前目录。


更好地交换订单并只使用它,os.path.dirname(os.path.abspath(__file__))因为这样您根本不必担心相对路径。一个更少的错误机会。
szali

3

我想为一个常见的场景(在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

3

如果您想从脚本中知道绝对路径,可以使用Path对象:

from pathlib import Path

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

cwd()方法

返回代表当前目录的新路径对象(由os.getcwd()返回)

resolve()方法

使路径绝对,解决任何符号链接。返回一个新的路径对象:


1

从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

因此,在上面,我必须从my_lib_a.py模块调用maincli.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的发布,我修改了代码。


1

如果您希望在“程序”中动态执行此操作,请尝试以下代码:
我的意思是,您可能不知道要对其“硬编码”的模块的确切名称。它可能是从列表中选择的,或者可能当前未运行以使用__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中进行仿真,因为它在程序中,因此可以轻松地放入方法或模块中重用。


0

如果您使用pip进行安装,则“ pip show”效果很好(“位置”)

$ pip show 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

0

这是一个快速的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 ~]#
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.