Python日志模块导入不同的脚本

Meh*_*IRA 2 python logging

在python日志教程中,有一个带有两个python脚本的例子:myapp.pymylib.py

代码是:

# myapp.py
import logging
import mylib

def main():
    logging.basicConfig(filename='myapp.log', level=logging.INFO)
    logging.info('Started')
    mylib.do_something()
    logging.info('Finished')

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

# mylib.py
import logging

def do_something():
    logging.info('Doing something')
Run Code Online (Sandbox Code Playgroud)

我没有得到的是如何使用basicConfigin myapp.py更改日志记录行为mylib.py.

我认为在Python中,当您在两个不同的脚本中导入相同的模块时,它们完全断开连接,因为第一个myapp.logging和第二个完成mylib.logging.

编辑:

我将mylib.py代码更改为

# mylib.py
import logging


def do_something():
    logging.warning('Doing something')


do_something()
Run Code Online (Sandbox Code Playgroud)

当我运行myapp.py时,日志现在在控制台中打印,不再出现在日志文件中.怎么可能?

tor*_*rek 7

在理解python的模块时有一个错误(如果我可以称之为):

我认为在Python中,当您在两个不同的脚本中导入相同的模块时,它们完全断开连接,因为第一个myapp.logging和第二个完成mylib.logging.

不是这种情况.

import遇到该语句时会解释该语句,当您在主程序(python myapp.py或等效程序)上运行python时,会执行以下行:

import logging
Run Code Online (Sandbox Code Playgroud)

(导入logging模块),

import mylib
Run Code Online (Sandbox Code Playgroud)

(导入你的图书馆mylib.py),

def main():
Run Code Online (Sandbox Code Playgroud)

(将名称绑定main到函数的已编译字节码),并且:

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

(运行你的,main因为本地名称__name__实际上绑定到一个比较等于字符串的字符串__main__).

到目前为止,这可能不是很令人惊讶(除了可能def main()是在导入时遇到的点myapp.py).

可能令人惊讶的部分在执行两个import语句期间发生的事情.

导入机制已经发展了一点(并且在Python3中与Python2有些不同)但实质上它做了以下各种事情:

  • 找到文件(使用sys.path)
  • 如果这是该文件的第一次导入,请运行该文件中的所有可执行语句
  • 使用或修改sys.modules(见下文)
  • 将结果对象(某些内容<type 'module'>或其中的名称)绑定到您提供的名称(隐式使用常规import,显式使用from ... import ... as name).

其中一个关键项目是上面的斜体部分.该模块实际上是在第一个模块上运行import.导入成功的结果是模块实例,它被添加到sys.modules字典中:

$ python2
...
>>> import sys
>>> x = sys.modules['copy_reg']
>>> print x
<module 'copy_reg' from '/usr/local/lib/python2.7/copy_reg.pyc'>
Run Code Online (Sandbox Code Playgroud)

如果,在这一点上,你要求python 重新导入模块,它将悄悄地几乎什么都不做:

>>> import copy_reg
>>> 
Run Code Online (Sandbox Code Playgroud)

这里发生的是Python注意到模块已经加载,sys.modules因此它只是提取已经加载的模块实体(我们也绑定到x上面的符号).然后它将名称绑定copy_reg到此已存在的模块.如果你import copy_reg as y:

>>> import copy_reg as y
Run Code Online (Sandbox Code Playgroud)

该名称另外绑定到符号y:

>>> print x, y, copy_reg
<module 'copy_reg' from '/usr/local/lib/python2.7/copy_reg.pyc'> <module 'copy_reg' from '/usr/local/lib/python2.7/copy_reg.pyc'> <module 'copy_reg' from '/usr/local/lib/python2.7/copy_reg.pyc'>
Run Code Online (Sandbox Code Playgroud)

要看到这些实际上是同一个模块,我们可以使用该id函数,它打印底层对象的内部地址:

>>> print id(x), id(y), id(copy_reg)
34367067648 34367067648 34367067648
Run Code Online (Sandbox Code Playgroud)

(不同的Python运行,或者不同的版本,可能会在这里产生不同的3组地址值,但这三个都匹配,因为这些都是指同一个模块).


在任何情况下,在你mainmyapp,符号logging是指相同的logging模块为标志loggingmylib.

在你的原代码,调用(来自do_somethingmylib)logging.warning打印的消息后,mainmyapp已调用日志记录配置代码.因此,日志消息按照指示进行.

在编辑中,一旦语句加载以创建模块,您就已经mylib无条件地调用(通过do_something)logging.warning函数.这种情况发生在早期,绑定到代码之前和调用之前.所以这个消息在控制台上出现了.import mylibmyilbmyappmainmain

由日志代码决定是否服从(稍后)basicConfig调用你的main.正如您在自己的示例中所看到的,它不会在打印消息后尝试重定向根配置(这是因为我记得当时它已经设置了内部日志处理程序).