题
我希望能够从导入的模块中动态检索当前正在执行的模块或类名。这是一些代码:
<强> 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”),这样每个应用程序的日志文件都会分别出现在各自的应用程序中。记录目录。
为了做到这一点,我认为最好的方法是记录器模块可以访问某种表示当前应用程序名称的全局变量,因为它负责了解父日志记录目录的位置并创建应用程序的日志目录(如果它尚不存在)。
解决方案
从评论中 - 不是问题。
我很想知道我想做的事情是否可行。
答案是“是否有可能”。始终是“是”。总是。除非您的问题涉及时间旅行,反重力或永久运动。
由于答案总是“是”,因此您的问题格式不正确。真正的问题是“让我的日志记录模块知道客户端名称的好方法是什么?”或类似的东西。
答案是“接受它作为参数”。不要乱搜查或寻找神秘的全局或其他技巧。
只需遵循logging.getLogger()的设计模式,并使用显式命名的记录器。一个常见的习语是以下
logger= logging.getLogger( __name__ )
几乎可以完美地处理所有日志命名。
其他提示
这应该适用于引用当前模块:
import sys
sys.modules[__name__]
“当前正在执行的模块”。显然是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__']
[编辑] :实际上,使用检查如上所述的模块可能是获得堆栈帧的更简洁的方法。等效代码是:
def f():
caller = inspect.currentframe().f_back
print "Called from module", caller.f_globals['__name__']
(sys._getframe记录为供内部使用 - 检查模块是更可靠的API)
__ file __
是调用当前模块的路径。
获取对“__ 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__
我不相信这是可能的,因为那是 foo
的范围。 foo只会知道它的内部范围,因为它可能被无数其他模块和应用程序调用。
单独使用 __ 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'。)
自从我完成python以来已经有一段时间了,但我相信你可以通过追溯。
如果您只想要文件名:
file_name = __file__.split("/")[len(__file__.split("/"))-1]
要获取包含文件夹的当前文件模块,这对我有用:
import os
parts = os.path.splitext(__name__)
module_name = parts[len(parts) - 2]