题
我想检测模块是否已更改。现在,使用 inotify 很简单,您只需要知道要从中获取通知的目录即可。
如何在 python 中检索模块的路径?
解决方案
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__)
获取模块的目录。
其他提示
在python中有 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 __
(下面再次演示)。但是,有一个重要的警告,即如果您自己运行模块(即 __ main __
),则 __ file __
不存在。
例如,假设您有两个文件(两者都在您的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
希望这会有所帮助。在测试所提出的其他解决方案时,这个警告花费了我很多时间和困惑。
我也会尝试解决这个问题的一些变化:
- 找到被调用脚本的路径
- 查找当前正在执行的脚本的路径
- 查找被调用脚本的目录 醇>
(其中一些问题已在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
file_import_testing_link - &gt; file_import_testing.py
使用检查
@SummerBreeze使用检查模块提及。
对于导入的模块,这似乎运行良好,而且非常简洁:
import os
import inspect
print 'inspect.getfile(os) is:', inspect.getfile(os)
顺从地返回绝对路径。但是,为了找到当前正在执行的脚本的路径,我没有看到使用它的方法。
我不明白为什么没有人在谈论这个,但对我来说最简单的解决方案是使用 imp.find_module(&quot; modulename&quot;)(文档here ):
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]。 spec 。如果碰巧是这样的话 设置为None,然后引发ValueError。如果模块不在 sys.modules,然后在sys.meta_path中搜索合适的规范 给予发现者的“路径”的价值。如果没有规范可以返回无 被发现。
如果名称用于子模块(包含点),则父模块为 自动导入。
name和package参数与importlib.import_module()的作用相同。 换句话说,相对模块名称(带有前导点)可以工作。
这是微不足道的。
每个模块都有一个 __ file __
变量,该变量显示了您现在所处的相对路径。
因此,获取模块通知它的目录很简单:
os.path.dirname(__file__)
import os
path = os.path.abspath(__file__)
dir_path = os.path.dirname(path)
命令行实用程序
您可以将其调整为命令行实用程序
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
所以我花了相当多的时间尝试使用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 module
print module.__path__
Packages支持另一个特殊属性
__ path __
。这是 初始化为包含目录保存名称的列表 在执行该文件中的代码之前,包&#8217;__ init __。py
。 这个变量可以修改;这样做会影响未来的搜索 包中包含的模块和子包。虽然通常不需要此功能,但可以使用它来扩展 在包中找到的一组模块。
您可以导入您的模块 然后点击它的名字,你会得到它的完整路径
>>> import os
>>> os
<module 'os' from 'C:\\Users\\Hassan Ashraf\\AppData\\Local\\Programs\\Python\\Python36-32\\lib\\os.py'>
>>>
如果使用 __ 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
诀窍是在 dirname()
调用之后的或'。'
。它将dir设置为。
,这意味着当前目录,并且是任何与路径相关的函数的有效目录。
因此,并不真正需要使用 abspath()
。但是如果你仍然使用它,不需要诀窍: abspath()
接受空白路径并正确地将其解释为当前目录。
我想贡献一个常见的场景(在 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() 返回路径结果基于 当前工作目录. 。一般不是我们想要的。第一个元素 系统参数 列表是 根脚本的路径 (您运行的脚本)无论您是在根脚本本身还是在其任何模块中调用该列表。在某些情况下它可能会派上用场。这 __文件__ 变量包含调用它的模块的路径。
以下代码正确创建文件 example.txt
在脚本所在的同一目录中:
filedir = os.path.dirname(os.path.realpath(__file__))
filepath = os.path.join(filedir, 'example.txt')
with open(filepath, 'w'):
pass
在python包的模块中,我必须引用与package位于同一目录中的文件。实施例
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的发布,我修改了代码。
如果您希望在“程序”中动态执行此操作,请执行此操作。试试这段代码:
我的观点是,您可能不知道模块的确切名称是“硬编码”。它。
它可以从列表中选择,也可能当前没有运行以使用__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中模拟 由于这是在程序中,因此可以很容易地将其放入方法或模块中以供重用。
如果您想知道脚本的绝对路径,可以使用 Path 对象:
from pathlib import Path
print(Path().absolute())
print(Path().resolve('.'))
print(Path().cwd())
返回一个表示当前目录的新路径对象(由os.getcwd()返回)
使路径绝对,解析任何符号链接。返回一个新的路径对象:
如果要从任何模块中检索包的根路径,以下工作(在Python 3.6上测试):
from . import __path__ as ROOT_PATH
print(ROOT_PATH)
也可以使用 __ file __
来引用主 __ init __。py
路径。
希望这有帮助!