‘import dataclasses’ 导致日志停止工作的原因是什么?

huangapple go评论50阅读模式
英文:

Why does 'import dataclasses' cause logging to stop working?

问题

我有以下的代码:

import logging
# import dataclasses

logging.basicConfig(
    filename="logfile.log",
    level=logging.DEBUG,
)

def main():
    logging.info("This is an info message")
    logging.error("This is an error message")

if __name__ == "__main__":
    main()

如果我注释掉 import dataclasses,日志将正常输出。但如果包括 import dataclasses,日志将完全停止输出。

有人知道为什么会这样吗?可能是个bug吗?

Python版本:3.9.16

英文:

I have the follow bit of code:

import logging
# import dataclasses

logging.basicConfig(
    filename="logfile.log",
    level=logging.DEBUG,
)

def main():
    logging.info("This is an info message")
    logging.error("This is an error message")

if __name__ == "__main__":
    main()

If I comment out import dataclasses the logs are outputted properly. But if I include import dataclasses it stops outputting completely.

Does anyone know why this is? Perhaps a bug?

Python version: 3.9.16

答案1

得分: 0

以下是您要翻译的内容:

这里似乎是导致我的问题的原因。我有以下简化的项目布局:

project/
script_one/
script_one.py
script_two/
script_two.py

script_one.py:

import logging

logging.basicConfig(
    filename="script_one.log",
    level=logging.DEBUG,
)

def main() -> None:
    logging.info("Starting script...")

if __name__ == "__main__":
    main()

script_two.py:

import logging
import dataclasses

logging.basicConfig(
    filename="logfile.log",
    level=logging.DEBUG,
)

def main():
    logging.info("This is an info message")
    logging.error("This is an error message")

if __name__ == "__main__":
    main()

问题在于script_one.py也在主函数之外包含了logging.basicConfig。显然,这导致了script_two.py中的日志输出到script_one.log,尽管只运行了script_two.py(这些脚本不相互导入)。

我好奇为什么Python会这样工作...
还有为什么import dataclasses会触发这个问题...

无论如何,解决方案是只需使用一个单独的记录器函数,并从主函数初始化:

script_one.py:

import logging

def logger():
	logging.basicConfig(
		filename="script_one.log",
		level=logging.DEBUG,
	)

def main() -> None:
    logger()
    logging.info("Starting script...")

if __name__ == "__main__":
    main()

script_two.py:

import logging
import dataclasses

def logger():
	logging.basicConfig(
		filename="logfile.log",
		level=logging.DEBUG,
	)

def main():
    logger()
    logging.info("This is an info message")
    logging.error("This is an error message")

if __name__ == "__main__":
    main()

----------------------编辑----------------------

我现在完全明白了在script_one.py中添加import traceback; traceback.print_stack()后发生的情况,正如@user2357112建议的那样:

File "/home/user/project/script_two/script_two.py", line 5, in <module>
	from dataclasses import dataclass
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 850, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/usr/lib/python3.9/dataclasses.py", line 3, in <module>
	import copy
File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 850, in exec_module
File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
File "/home/user/project/copy/copy.py", line 8, in <module>
	traceback.print_stack()

事实上,我在示例中使用的script_one.py实际上被称为copy.py。由于dataclasses导入了copy模块,它实际上导入了我的copy.py,然后运行了日志记录语句,将日志输出到另一个文件。

谜题解决了!

英文:

So here's what seems to be causing my issue. I have the following simplified project layout:

project/
  script_one/
    script_one.py
  script_two/
    script_two.py

script_one.py:

import logging

logging.basicConfig(
    filename=&quot;script_one.log&quot;,
    level=logging.DEBUG,
)

def main() -&gt; None:
    logging.info(&quot;Starting script...&quot;)

if __name__ == &quot;__main__&quot;:
    main()

script_two.py:

import logging
import dataclasses

logging.basicConfig(
    filename=&quot;logfile.log&quot;,
    level=logging.DEBUG,
)

def main():
    logging.info(&quot;This is an info message&quot;)
    logging.error(&quot;This is an error message&quot;)

if __name__ == &quot;__main__&quot;:
    main()

The problem is that script_one.py also contains logging.basicConfig outside of the main function. Apparently this caused the logs in script_two.py to be output to script_one.log, despite only running script_two.py (these scripts don't import each other).

I am curious why Python works this way...
And also why import dataclasses triggers this issue...

Anyway, the solution is to just use a separate logger function and initialize from main:

script_one.py:

import logging

def logger():
	logging.basicConfig(
		filename=&quot;script_one.log&quot;,
		level=logging.DEBUG,
	)

def main() -&gt; None:
    logger()
    logging.info(&quot;Starting script...&quot;)

if __name__ == &quot;__main__&quot;:
    main()

script_two.py:

import logging
import dataclasses

def logger():
	logging.basicConfig(
		filename=&quot;logfile.log&quot;,
		level=logging.DEBUG,
	)

def main():
    logger()
    logging.info(&quot;This is an info message&quot;)
    logging.error(&quot;This is an error message&quot;)

if __name__ == &quot;__main__&quot;:
    main()

----------------------EDIT----------------------

I now fully understand what was happening after placing import traceback; traceback.print_stack() in script_one.py as suggested by @user2357112:

File &quot;/home/user/project/script_two/script_two.py&quot;, line 5, in &lt;module&gt;
	from dataclasses import dataclass
File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 1007, in _find_and_load
File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 986, in _find_and_load_unlocked
File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 680, in _load_unlocked
File &quot;&lt;frozen importlib._bootstrap_external&gt;&quot;, line 850, in exec_module
File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 228, in _call_with_frames_removed
File &quot;/usr/lib/python3.9/dataclasses.py&quot;, line 3, in &lt;module&gt;
	import copy
File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 1007, in _find_and_load
File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 986, in _find_and_load_unlocked
File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 680, in _load_unlocked
File &quot;&lt;frozen importlib._bootstrap_external&gt;&quot;, line 850, in exec_module
File &quot;&lt;frozen importlib._bootstrap&gt;&quot;, line 228, in _call_with_frames_removed
File &quot;/home/user/project/copy/copy.py&quot;, line 8, in &lt;module&gt;
	traceback.print_stack()

As it so happens, my script_one.py that I used in the example was actually called copy.py. Since dataclasses imports the copy module, it instead imports my copy.py which then runs the logging statement, outputting to the other file.

Mystery solved!

huangapple
  • 本文由 发表于 2023年6月11日 21:45:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/76450767.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定