【问题标题】:How can I access the current executing module or class name in Python?如何在 Python 中访问当前正在执行的模块或类名?
【发布时间】:2010-10-10 19:28:42
【问题描述】:

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

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

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

【问题讨论】:

  • 为什么要这样打破责任分配?
  • 我在日志模块中使用它 - 我希望能够判断哪个外部模块正在尝试记录,而调用者不必传递某种密钥。
  • 您是否正在寻找启动程序执行的模块(即:name == 'main' 的模块?调用 foo.f() 的模块,每次调用 foo.f() 时可能不同?
  • @Andrew Hare:您是说 (a) 您编写了自己的记录器,与内置的日志记录模块不同,并且 (b) 您自己的记录器没有简单的配置类或函数?你想解决这个问题吗?
  • @S.Lott - a) 是,b) 是,而且根本没有解决方法 - 只是稍微了解一下。

标签: python module


【解决方案1】:

来自评论——不是问题。

我只是想知道我正在尝试做的事情是否可行。

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

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

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

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

logger= logging.getLogger( __name__ )

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

【讨论】:

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

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

import sys
sys.modules[__name__]

【讨论】:

  • 然后你可以使用import sys; module_name = vars(sys.modules[__name__])['__package__']获取当前模块的名称,如果不是模块则使用None。例如:如果代码使用python foo/bar.py 执行,module_name 将是None;但是对于python -m foo.barmodule_name 将是"foo"
【解决方案3】:

“当前执行的模块”显然是 foo,因为它包含当前正在运行的函数 - 我认为关于你想要的更好的描述是 foo 的直接调用者的模块(如果你正在调用,它本身可能是 foo af() 来自 foo 中的函数,由 bar 中的函数调用。你想上升多远取决于你想要这个。

在任何情况下,假设您想要直接调用者,您可以通过向上调用堆栈来获得它。这可以通过调用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)

【讨论】:

    【解决方案4】:

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

    【讨论】:

      【解决方案5】:

      在另一个模块中获取对“__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__
      

      【讨论】:

      • 使用 file 不起作用如果你在一个包中如果你有 foo/__init__.py,file 将返回 init.py 而不是 foo
      【解决方案6】:

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

      【讨论】:

        【解决方案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
        

        结果:

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

        【讨论】:

        • 有什么理由使用__file__.split(os.path.sep)[-1] 而不是os.path.basename(__file__) 吗?
        【解决方案8】:

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

        【讨论】:

          【解决方案9】:

          如果你只想要文件名:

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

          【讨论】:

          • 对于跨平台解决方案,请考虑使用os.path。此外,您可以只使用-1 作为索引。
          【解决方案10】:

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

          【讨论】:

            【解决方案11】:

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

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

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2010-12-26
              • 2011-07-08
              • 2021-12-29
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-06-04
              相关资源
              最近更新 更多