925

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

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

4

22 回答 22

1123
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__)

获取模块的目录。

于 2008-10-29T23:57:13.760 回答
327

python中有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'
于 2012-08-28T07:24:09.850 回答
80

正如其他答案所说,最好的方法是使用__file__(在下面再次演示)。但是,有一个重要的警告,如果您自己运行模块(即 as ) ,__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 

希望这可以帮助。在测试提出的其他解决方案时,这个警告花费了我很多时间和困惑。

于 2011-06-20T19:05:40.220 回答
62

我也会尝试解决这个问题的一些变化:

  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.py 的符号链接 file_import_testing_link,其内容如下:

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

文件导入测试链接-> 文件导入测试.py

使用检查

@SummerBreeze 提到使用检查模块。

对于导入的模块,这似乎运行良好,并且非常简洁:

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

乖乖返回绝对路径。查找当前执行脚本的路径:

inspect.getfile(inspect.currentframe())

(感谢@jbochi)

inspect.getabsfile(inspect.currentframe()) 

给出当前执行脚本的绝对路径(感谢@Sadman_Sakib)。

于 2013-05-30T02:15:40.017 回答
43

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

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

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

于 2015-03-11T00:10:44.000 回答
22

这是微不足道的。

每个模块都有一个__file__变量,显示您现在所在位置的相对路径。

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

os.path.dirname(__file__)
于 2008-10-29T19:18:15.320 回答
17
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)
于 2010-12-13T17:35:17.707 回答
15
import module
print module.__path__

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

虽然通常不需要此功能,但它可用于扩展包中的模块集。

来源

于 2014-08-16T23:04:03.010 回答
11

命令行实用程序

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

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
于 2015-08-15T16:27:18.247 回答
8

你可以只导入你的模块然后点击它的名字,你会得到它的完整路径

>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>
于 2018-08-29T15:39:10.843 回答
6

所以我花了相当多的时间尝试用 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__))
于 2012-03-18T16:28:43.550 回答
6

如果你想从它的任何模块中检索包的根路径,以下工作(在 Python 3.6 上测试):

from . import __path__ as ROOT_PATH
print(ROOT_PATH)

__init__.py也可以通过 using 来引用主路径__file__

希望这可以帮助!

于 2019-03-31T23:03:39.663 回答
5

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

from pathlib import Path

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

cwd() 方法

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

解析()方法

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

于 2018-10-06T13:04:45.020 回答
5

导入模块时,您可以访问大量信息。退房dir(a_module)。至于路径,有一个dunder 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'>
于 2020-11-12T08:53:23.883 回答
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()接受空白路径并将其正确解释为当前目录。

于 2014-08-15T01:22:39.707 回答
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
于 2018-04-22T16:54:04.760 回答
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'>

我试图摆脱“全局”问题,但发现它不起作用的情况我认为可以在 Python 3 中模拟“execfile()”由于这是在程序中,因此可以轻松地将其放入方法或模块中重用。

于 2015-01-14T01:23:25.097 回答
1

在 python 包的模块中,我必须引用与 package.json 位于同一目录中的文件。前任。

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 的发布,我修改了代码。

于 2015-05-12T13:27:01.890 回答
1

如果要检索模块路径而不加载它:

import importlib.util

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

示例输出:

/usr/lib64/python3.9/site-packages/requests/__init__.py
于 2022-01-08T06:11:24.603 回答
0

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

$ pip 显示检测器2

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

更新:

$ python -m pip 显示我的模块

(作者:维斯巴基)

于 2020-01-31T13:57:45.453 回答
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 ~]#
于 2020-02-10T17:51:18.237 回答
0

如果您使用pip,那么您可以调用pip show,但您必须使用python您正在使用的特定版本来调用它。例如,这些都可能给出不同的结果:

$ 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版本调用的相同。

于 2021-08-29T20:54:06.820 回答