英文:
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="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()
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="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()
----------------------EDIT----------------------
I now fully understand what was happening after placing import traceback; traceback.print_stack() in script_one.py as suggested by @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()
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!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论