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

And*_*are 45 python module

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

foo.py:

def f():
    print __name__
Run Code Online (Sandbox Code Playgroud)

bar.py:

from foo import f

def b(): f()
Run Code Online (Sandbox Code Playgroud)

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

编辑:inspect模块看起来非常有前途,但它并不完全是我想要的.我希望的是我可以访问的某种全局或环境级变量,它包含当前执行模块的名称.并不是说我不愿意遍历堆栈来查找信息 - 我只是认为Python可能已经暴露了这些数据.

编辑:这是我试图使用它的方式.我有两个不同的Django应用程序,它们都需要将错误记录到文件中.让我们说它们被称为"AppOne"和"AppTwo".我还有一个地方可以记录这些文件:" /home/hare/app_logs".在任何给定点的每个应用程序中,我希望能够导入我的记录器模块并调用将日志字符串写入文件的日志功能.但是,我想要做的是创建一个目录,app_logs该目录是当前应用程序的名称("AppOne"或"AppTwo"),以便每个应用程序的日志文件将进入各自的日志记录目录.

为了做到这一点,我认为最好的办法是对记录器模块能够获得某种形式的全局变量,它表示当前应用程序的名称,因为它是负责了解父日志目录的位置,并创建应用程序的日志目录,如果它还不存在.

S.L*_*ott 49

从评论 - 不是问题.

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

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

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

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

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

logger= logging.getLogger( __name__ )
Run Code Online (Sandbox Code Playgroud)

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

  • 虽然如果我运行脚本而不是导入它,`__name__`将包含`__main__`而不是脚本的真实路径(如`modA.submodB.pack1`).有没有*总是*返回模块路径的值,无论它如何被调用? (11认同)
  • "'有可能'的答案总是'是'." 或者在多项式时间内解决NP问题.然后它"可能,但大多数人认为不是".;) (5认同)
  • 实际上python中有一个反重力模块(虽然不确定时间旅行和永动) (4认同)
  • 我认为您是对的,因为我会更好地调整自己的方法-谢谢! (2认同)
  • @estani:如果你将它作为脚本运行,它的名字将是*'__main__`。以这种方式运行时,没有模块“真实”名称或 `modA.submodB.pack1` 这样的东西。不要将模块层次结构与文件名混淆。 (2认同)

new*_*ver 34

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

import sys
sys.modules[__name__]
Run Code Online (Sandbox Code Playgroud)

  • 然后你可以使用`import sys; module_name = vars(sys.modules[__name__])['__package__']` 获取当前模块的名称,如果不是模块,则获取 `None` 。例如:如果使用“python foo/bar.py”执行代码,*module_name*将为“None”;但使用 `python -m foo.bar` 时,*module_name* 将是 `"foo"`。 (3认同)

Bri*_*ian 19

"当前正在执行的模块"显然是foo,因为它包含当前正在运行的功能 - 我认为更好的描述你想要的是foo的直接调用者的模块(如果你调用af(这可能本身就是foo)从一个函数调用foo函数调用吧.你想要达到多远取决于你想要的东西.

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

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

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

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

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


utk*_*tas 12

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


nst*_*ehr 11

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

  • 链接坏了. (7认同)

Sjs*_*van 11

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

import sys
sys.modules['__main__']
Run Code Online (Sandbox Code Playgroud)

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

sys.modules['__main__'].__file__
Run Code Online (Sandbox Code Playgroud)

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

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

import os
os.path.basename(file_path)
Run Code Online (Sandbox Code Playgroud)

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

file_name.split(".")[0]
Run Code Online (Sandbox Code Playgroud)

要获取类实例的名称:

instance.__class__.__name__
Run Code Online (Sandbox Code Playgroud)

获取类名:

class.__name__
Run Code Online (Sandbox Code Playgroud)


Bru*_*sky 7

单独使用__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
Run Code Online (Sandbox Code Playgroud)

结果:

## 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'}
Run Code Online (Sandbox Code Playgroud)

如果你想去掉末尾的“.py”,你可以轻松做到。(但不要忘记您可以运行“.pyc”。)

  • 有什么理由使用 `__file__.split(os.path.sep)[-1]` 而不是 `os.path.basename(__file__)` ? (4认同)

Ric*_*oCh 5

如果您只需要文件名:

file_name = __file__.split("/")[len(__file__.split("/"))-1]
Run Code Online (Sandbox Code Playgroud)

  • 对于跨平台解决方案,请考虑使用“os.path”。另外,您可以只使用“-1”作为索引。 (3认同)