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

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


当前回答

如果你想在不加载的情况下检索模块路径:

import importlib.util

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

示例输出:

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

其他回答

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'

这是微不足道的。

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

因此,为模块获取一个目录来通知它很简单,如下所示:

os.path.dirname(__file__)

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

查找被调用脚本的路径 查找当前执行脚本的路径 查找被调用脚本的目录

(其中一些问题已经在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提到了使用inspect模块。

对于导入的模块,这似乎工作得很好,而且相当简洁:

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

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

inspect.getfile(inspect.currentframe())

(感谢@jbochi)

inspect.getabsfile(inspect.currentframe()) 

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

正如其他答案所说,最好的方法是使用__file__(下面再次演示)。然而,有一个重要的警告,即如果你单独运行模块(即作为__main__), __file__是不存在的。

例如,假设你有两个文件(都在你的PYTHONPATH上):

#/path1/foo.py
import bar
print(bar.__file__)

and

#/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 

希望这能有所帮助。在测试其他解决方案时,这个警告花费了我大量的时间和混乱。

命令行实用程序

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

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