如何获取当前运行模块的路径/名称

44
我已经搜索了一下,这似乎是一个简单问题但没有简单的答案。 我有文件a/b/c.py,它将使用python -m a.b.c进行调用。我想在模块级别获取值a.b.c。
USAGE = u'''\
Usage:
    python -m %s -h
''' % (what_do_i_put_here,)

所以当我收到-h选项时,我会显示USAGE,而不需要在每个脚本中写下实际值。

我真的需要通过inspect来获取所需的值吗?

谢谢。

编辑:正如所说,有答案(我已经搜索过),但没有简单的答案。要么使用inspect,要么使用traceback,要么操作__file____package__并执行一些子字符串以获取答案。但是,如果我在模块中有一个类,我只需使用myClass.__module__,我就可以得到想要的答案。不幸的是,__name__的使用是无用的,因为它总是"__main__"

此外,这是在Python 2.6中,我不能使用任何其他版本。


这个线程对你有帮助吗?https://dev59.com/dHVC5IYBdhLWcg3wliKe - wkl
有多个重复的候选项:https://dev59.com/Rm855IYBdhLWcg3wiU31,https://dev59.com/9XM_5IYBdhLWcg3wRw11 - André Caron
1
我认为这不是一个重复的问题:在之前的评论中,提到的问题旨在获取文件系统上执行文件的路径,而 PO 想要获取当前 Python + 模块 - gecco
8个回答

31
这对我有效:
__loader__.fullname

如果我在a\下执行python -m b.c,那么我会得到预期的'b.c'。

不太确定__loader__属性是什么,所以如果这样不行请告诉我。

编辑:它来自PEP 302:http://www.python.org/dev/peps/pep-0302/

链接中的有趣片段:

在运行任何代码之前,load_module()方法必须履行一些职责:

...

  • 它应该向模块添加一个__loader__属性,并将其设置为加载器对象。 这主要用于内省,但可以用于特定于导入程序的额外功能,例如获取与导入程序关联的数据。

因此,在所有情况下看起来都应该正常工作。


9
对我来说,它需要是__loader__.name。参见 https://docs.python.org/3/library/importlib.html#importlib.abc.FileLoader 的文档。 - ronen

19

我认为你实际上是在寻找特殊变量__name__。根据Python文档的描述:

在一个模块内,模块名称作为一个字符串可以通过全局变量__name__得到。

如果你直接运行一个文件,这个名称将会是__main__。然而,如果你在一个模块中(如使用-m标志时或任何其他导入操作),它将是完整的模块名称。


10
如果使用“-m”标志调用,_name_将会是“main”。 - Danosaure
如果您想以更Pythonic的方式在cmd或终端中获取模块名称而不使用-m选项,或者不想使用loader,那么您可能会对我的答案感兴趣。它是一行代码,使用字符串操作。谢谢。 - nikhil swami
在我的情况下,我需要一系列子模块的主模块,例如 tf.keras.layers。因此,我使用了 __name__.split('.')[0] - J Agustin Barrachina

10

谢谢,我编辑了我的问题以指出我知道如何操作得到答案,但我希望有一种更简单的方式而不必自己验证。 - Danosaure
您的意思是 sys.argv[0] - CristiFati

7

有多种方法可以获取当前模块的路径/名称。

首先要熟悉Python中__file__的用法,点击此处查看用法

它保存了当前加载的模块的名称。

检查/尝试以下代码,它将在Python2Python3上工作。

» module_names.py

import os

print (__file__)
print (os.path.abspath(__file__))
print (os.path.realpath(__file__))

在MAC OS X上的输出:
MacBook-Pro-2:practice admin$ python module_names.py 
module_names.py
/Users/admin/projects/Python/python-the-snake/practice/module_names.py
/Users/admin/projects/Python/python-the-snake/practice/module_names.py

这里我们得到了当前模块名称及其绝对路径


0

唯一的方法是使用os.getcwd()、os.path、file等进行路径操作,正如你所提到的。

实际上,这可能是一个很好的补丁,可以用于optparse / argparse(目前将使用字符串中的“%prog”替换为os.path.basename(sys.argv[0]) -- 你正在使用optparse吗?--),即另一个特殊字符串,如%module。


我仍然在使用一个公司的软件包,它仍然使用getopt模块。该模块是在2006-2007年创建的。 - Danosaure

-2
为什么没有人提到 .__module__
当执行 self.__module__ 时,您将获得模块路径。 您也可以在类外部执行此操作:
Class A:
   self.__module__  # gets module.filename

def get_module():
    A.__module__ # also gets module.filename

感谢您的评论和点踩。我没有看到您的编辑,所以我想这是公平的。 - Nebulosar

-2

一行代码但受操作系统限制

在解释器中无法正常工作!因为file在解释器中没有意义且未被定义。

不需要导入os模块。

modulename=__file__.split("\\")[-1].split('.')[0]

解释: X:\apple\pythonabc.py | 将输出 pythonabc.py

选择斜杠分割后的最后一个元素,然后通过点“.”进行分割选择第一个元素。因为第一步得到 module.py,第二步只得到“module”。__file__是一个独特的变量,返回当前模块的文件路径。

请评论是否有任何缺陷或其他陷阱。


你能否删除指向自己答案的其他回答中的评论?这样做会浪费别人的时间,也是不礼貌的行为。如果你的答案很好,它会自然而然地上升到顶部;如果不好,你就在推广一个错误的答案。 - cjs
你有没有尝试使用问题开头给出的示例路径/文件和python命令来测试? - cjs
python -m test 可以执行 test 模块的测试,但对于 test.b.c 模块则不行。这在一定程度上回答了提问者的问题。如果有人通过谷歌搜索到这里,可能会得到其他想法。解决问题的方法有很多种,有时候简单并不是唯一的解决方案。 - nikhil swami
1
它甚至没有部分回答,因为OP想要模块名称,而[Python文件名不是模块名称](https://dev59.com/omsz5IYBdhLWcg3wWmjL#49420164)。 - cjs

-3

如果您将软件包分发为这样的形式,那么在帮助文档中应该硬编码a.b.c,无论a在文件系统中的位置如何,只要它在PYTHONPATH上,就可以调用它。


如果更改文件名,所有导入都将中断,因此帮助文本是您问题中较小的部分。 - Samus_
如果你有理由,不同意也没关系,问题在于入口点通常不会被导入,而是直接执行,所以在那种情况下并不重要。但是在这里你谈论的是导入,所以这就是一个不同的问题,而不合理的地方在于你导入了入口点,这就是矛盾之处。 - Samus_
是的,因为更改您执行的文件名不重要,如果它是入口点,您不需要知道'a.b.c',因为您不会执行'python -m a.b.c',而是执行'python 文件名'。 - Samus_
但这正是我的重点,为什么要用“python -m a.b.c”而不是“python文件”呢?如果你问一些无意义的问题,我会指出来,我不在乎是否回答你的问题,真正的答案是“你做错了”。 - Samus_
那是你的观点。我使用 "python -m a.b.c",因为我想要将脚本与我的 Python 模块一起安装。我不想污染 /usr/local/bin 或任何虚拟环境/bin。这样做,我可以通过使用错误的模块和错误的 Python 环境来保护自己。 - Danosaure
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接