如何在python中访问当前正在执行的模块或类名?

How can I access the current executing module or class name in Python?

我希望能够动态地从导入的模块中检索当前正在执行的模块或类名。下面是一些代码:

PY.PY:

1
2
def f():
    print __name__

bar.py:

1
2
3
from foo import f

def b(): f()

这显然不起作用,因为__name__是包含函数的模块的名称。我想在foo模块中访问的是当前正在使用foo的执行模块的名称。因此,在上面的情况下,它将是bar,但是如果任何其他模块导入foo,我希望foo能够动态访问该模块的名称。

编辑:inspect模块看起来很有前途,但它并不是我想要的。我希望得到的是某种全局或环境级别的变量,我可以访问这些变量,其中包含当前执行模块的名称。并不是说我不愿意遍历堆栈来找到这些信息——我只是认为Python可能已经公开了这些数据。

编辑:这是我使用这个的方法。我有两个不同的django应用程序,它们都需要将错误记录到文件中。假设它们被称为"appone"和"apptwo"。我还有一个地方可以记录这些文件:"/home/hare/app_logs"。在任何给定点的每个应用程序中,我希望能够导入记录器模块并调用将日志字符串写入文件的日志函数。不过,我想做的是在app_logs下创建一个目录,即当前应用程序的名称("appone"或"apptwo"),以便每个应用程序的日志文件都进入各自的日志目录。

为了做到这一点,我认为最好的方法是让logger模块能够访问某种表示当前应用程序名称的全局变量,因为它负责知道父日志目录的位置,并创建应用程序的日志目录(如果还不存在的话)。


从评论中——而不是问题中。

I am simply curious to see if what I am trying to do is possible.

"有可能"的答案总是"是"。总是。除非你的问题涉及到时间旅行、反重力或永久运动。

因为答案总是"是",所以你的问题是不正确的。真正的问题是"什么是让我的日志模块知道客户机名称的好方法?"或者类似的。

答案是"接受它作为一个参数",不要乱检查或寻找神秘的全局或其他技巧。

只需遵循logging.getlogger()的设计模式并使用显式命名的记录器。一个常见的成语是

1
logger= logging.getLogger( __name__ )

它可以完美地处理几乎所有的日志命名。


这应该适用于引用当前模块:

1
2
import sys
sys.modules[__name__]


"当前正在执行的模块"显然是foo,因为它包含当前正在运行的函数——我认为对于您想要的是foo的直接调用方的模块(如果您从foo中的函数调用f(),那么它本身可能是foo)。你想走多远取决于你想做什么。

在任何情况下,假设您需要立即调用方,您可以通过遍历调用堆栈来获得这一点。这可以通过调用sys._getframe来实现,它具有正确的步行级别数。

1
2
3
def f():
    caller = sys._getframe(1)  # Obtain calling frame
    print"Called from module", caller.f_globals['__name__']

[编辑]:实际上,按照上面的建议使用inspect模块可能是获得堆栈帧的一种更干净的方法。等效代码为:

1
2
3
def f():
    caller = inspect.currentframe().f_back
    print"Called from module", caller.f_globals['__name__']

(系统框架记录为供内部使用-检查模块是一个更可靠的API)


我认为您希望使用inspect模块来检查python运行时堆栈。看看这个教程。我认为它提供了一个你想要做什么的几乎精确的例子。


__file__是调用当前模块的路径。


要在另一个模块中获取对"主"模块的引用,请执行以下操作:

1
2
import sys
sys.modules['__main__']

然后获取模块的文件路径,其中包括其名称:

1
sys.modules['__main__'].__file__

如果在"主"模块中,只需使用:__file__

仅从文件路径获取文件名:

1
2
import os
os.path.basename(file_path)

要将文件名与其扩展名分开,请执行以下操作:

1
file_name.split(".")[0]

要获取类实例的名称,请执行以下操作:

1
instance.__class__.__name__

要获取类的名称:

1
class.__name__


单独使用__file__可以为主模块提供相对路径,为导入的模块提供绝对路径。意识到这一点,我们可以通过任何一种方式不断获得模块文件,只需借助于我们的os.path工具。

对于文件名,只使用__file__.split(os.path.sep)[-1]

完整路径使用os.path.abspath(__file__)

演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/tmp $ cat f.py
from pprint import pprint
import os
import sys

pprint({
    'sys.modules[__name__]': sys.modules[__name__],
    '__file__': __file__,
    '__file__.split(os.path.sep)[-1]': __file__.split(os.path.sep)[-1],
    'os.path.abspath(__file__)': os.path.abspath(__file__),
})

/tmp $ cat i.py
import f

结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
## on *Nix ##

/tmp $ python3 f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': '/tmp/f.py'}

/tmp $ python3 i.py
{'sys.modules[__name__]': <module 'f' from '/tmp/f.pyc'>,
 '__file__': '/tmp/f.pyc',
 '__file__.split(os.path.sep)[-1]': 'f.pyc',
 'os.path.abspath(__file__)': '/tmp/f.pyc'}

## on Windows ##

PS C:\tmp> python3.exe f.py
{'sys.modules[__name__]': <module '__main__' from 'f.py'>,
 '__file__': 'f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

PS C:\tmp> python3.exe i.py
{'sys.modules[__name__]': <module 'f' from 'C:\\tools\\cygwin\\tmp\\f.py'>,
 '__file__': 'C:\\tools\\cygwin\\tmp\\f.py',
 '__file__.split(os.path.sep)[-1]': 'f.py',
 'os.path.abspath(__file__)': 'C:\\tools\\cygwin\\tmp\\f.py'}

如果你想从末尾去掉".py",你可以很容易地做到。(但不要忘记,您可以运行一个".pyc")。


我认为这是不可能的,因为这超出了foo的范围。FOO将只知道它的内部作用域,因为它可能被无数其他模块和应用程序调用。


我已经有一段时间没有做过python了,但我相信您可以通过它的回溯来访问调用者的全局和局部变量。


如果只需要文件名:

1
file_name = __file__.split("/")[len(__file__.split("/"))-1]


要获取包含文件夹的当前文件模块,以下是对我有效的:

1
2
3
 import os
 parts = os.path.splitext(__name__)
 module_name = parts[len(parts) - 2]