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

时间:2009-03-02 15:55:53

标签: python module

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

foo.py:

def f():
    print __name__

bar.py:

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”),这样每个应用程序的日志文件都会进入各自的日志目录。

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

11 个答案:

答案 0 :(得分:46)

从评论中 - 不是问题。

  

我很想知道我想做的事情是否可行。

“有可能”的答案总是“是”。总是。除非您的问题涉及时间旅行,反重力或永久运动。

由于答案总是“是”,你的问题是不正确的。真正的问题是“让我的日志记录模块知道客户端名称的好方法是什么?”或类似的东西。

答案是“将其作为参数接受”。不要乱搜查或寻找神秘的全局或其他技巧。

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

logger= logging.getLogger( __name__ )

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

答案 1 :(得分:30)

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

import sys
sys.modules[__name__]

答案 2 :(得分:19)

“当前正在执行的模块”显然是foo,因为它包含当前正在运行的功能 - 我想更好地描述你想要的是foo的直接调用者的模块(如果你正在调用它本身可能是foo af()来自foo函数,由一个函数调用吧。你想要达到的程度取决于你想要的东西。

在任何情况下,假设您想要直接调用者,您可以通过向上调用堆栈来获得此调用者。这可以通过调用sys._getframe来完成,并且要有适当数量的等级来行走。

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

[编辑] :实际上,如上所述使用inspect模块可能是获取堆栈帧的更简洁方法。等效代码是:

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

(sys._getframe记录为供内部使用 - 检查模块是更可靠的API)

答案 3 :(得分:11)

我认为您要使用的是inspect模块,以检查python运行时堆栈。看看这个tutorial。我认为它提供了你想要做的几乎完全的例子。

答案 4 :(得分:10)

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

答案 5 :(得分:4)

在另一个模块中获取对“__main__”模块的引用:

import sys
sys.modules['__main__']

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

sys.modules['__main__'].__file__

如果在“__main__”模块中,只需使用:__file__

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

import os
os.path.basename(file_path)

将文件名与其扩展名分开:

file_name.split(".")[0]

获取类实例的名称:

instance.__class__.__name__

获取班级名称:

class.__name__

答案 6 :(得分:3)

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

答案 7 :(得分:3)

单独使用__file__为您提供主模块的相对路径和导入模块的绝对路径。意识到这一点,我们可以通过os.path工具的一些帮助,无论如何都可以获得模块文件。

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

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

演示:

/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

结果:

## 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'。)

答案 8 :(得分:2)

自从我完成python以来已经有一段时间了,但我相信你可以通过traceback访问调用方的全局变量和本地变量。

答案 9 :(得分:1)

如果您只想要文件名:

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

答案 10 :(得分:0)

要获取包含文件夹的当前文件模块,这对我有用:

RequestController.java